1. 项目概述:为什么需要父子模块的POM继承?
在任何一个有一定规模的Java项目中,你迟早会遇到一个头疼的问题:依赖管理。想象一下,你手头有五个、十个甚至二十个独立的服务或模块,它们都需要使用同一个版本的Spring Boot、同一个版本的Jackson库,或者同一个数据库驱动。如果每个模块的pom.xml里都各自写一遍这些依赖,那简直就是一场维护噩梦。今天你升级了Spring Boot版本,明天就得手动去改几十个文件,稍有不慎就会导致版本冲突,项目直接跑不起来。
Maven的父子模块继承机制,就是为了解决这个“配置地狱”而生的。它允许你创建一个“父”POM(Project Object Model),将那些公共的、需要统一管理的配置——比如依赖项、插件、仓库地址、甚至构建属性——都定义在里面。然后,各个“子”模块的Pom.xml可以简单地声明自己继承自这个父POM,从而自动获得所有这些配置。这不仅仅是复制粘贴,而是一种声明式的、中心化的管理方式。
我见过太多项目初期为了图省事,每个模块都“独立自主”,结果到了中后期,技术栈升级、安全漏洞修复时,团队耗费大量时间在比对和同步配置上,效率极低且容易出错。父子模块继承,是Maven项目迈向规范化、可维护性的第一步。它特别适合微服务架构、多模块单体应用,或者任何需要将代码按功能、层级进行物理拆分的大型项目。无论你是刚接触Maven的新手,还是正在为混乱的依赖管理而烦恼的资深开发者,理解并运用好这个机制,都能让你的构建过程清晰、高效数倍。
2. 核心机制与设计思路拆解
2.1 继承的本质:不仅仅是复制
很多初学者会把继承理解为简单的“复制父POM的内容到子POM”,这是一个常见的误解。Maven的继承机制远比这精巧。子模块的POM并不是在物理上包含了父POM的所有XML节点,而是在解析和构建时,Maven会动态地将父子POM合并成一个“有效POM”。
这个合并过程遵循一套明确的规则:
- 模型合并:子POM中定义的任何元素,都会覆盖父POM中同名的元素。例如,父POM定义了
<version>1.0</version>,子POM定义了<version>2.0</version>,那么最终生效的是2.0。 - 列表合并:对于像
<dependencies>、<plugins>这样的列表元素,处理方式不是覆盖,而是追加。子POM的依赖会添加到父POM的依赖列表之后。这非常重要,意味着子模块会自动拥有父模块声明的所有依赖,同时还可以添加自己独有的依赖。 - 属性继承与覆盖:在
<properties>中定义的属性会被完全继承。子POM可以重新定义同名属性以覆盖父POM的值,这个覆盖会影响所有引用该属性的地方。
这种设计思路的核心优势在于“约定优于配置”和“单一事实来源”。团队约定好公共依赖的版本在父POM中定义,这就是唯一的真相。任何子模块都无需再关心这些公共依赖的具体版本号,只需关心自己业务特有的依赖。这极大地降低了配置的复杂度和出错的概率。
2.2 父POM的类型:pom与聚合
在父POM的<packaging>元素中,你必须将其设置为pom。这明确告诉Maven:这个项目不是一个会被打包成jar或war的代码模块,而是一个纯粹的配置管理容器。
<!-- 父模块的 pom.xml --> <project> <modelVersion>4.0.0</modelVersion> <groupId>com.example</groupId> <artifactId>parent-project</artifactId> <version>1.0.0</version> <packaging>pom</packaging> <!-- 关键! --> ... </project>同时,父POM通常也扮演着聚合模块的角色。这意味着在父POM的根目录下,会有一个<modules>列表,声明了它所包含的所有子模块。这样,在父目录下执行mvn clean install,Maven会按照依赖顺序自动构建所有子模块,非常方便。
<!-- 父POM中声明子模块 --> <modules> <module>core-service</module> <module>web-api</module> <module>data-access</module> </modules>实操心得:我强烈建议将“父POM”和“聚合模块”合二为一。即用一个顶层的、packaging为pom的项目,既管理公共配置,又聚合所有子模块。这样项目结构最清晰。除非项目结构极其复杂(比如多个完全独立的产品线共享一个父POM),否则没必要分开。
2.3 关键配置项的继承范围
不是父POM中的所有配置都能被子模块继承。理解哪些能、哪些不能,是避免踩坑的关键。
肯定会被继承的配置:
- 项目坐标:
<groupId>和<version>通常会被继承。子模块可以省略它们,Maven会自动使用父POM的值。这是一种常见的简化写法。但<artifactId>必须每个子模块唯一,所以不会被“继承”覆盖。 - 依赖管理:
<dependencyManagement>节中的依赖声明。这是Maven依赖管理的精髓,我们稍后详细讲。 - 插件管理:
<pluginManagement>节中的插件声明。与依赖管理类似,用于统一管理插件版本和配置。 - 属性:
<properties>中定义的所有属性。 - 仓库与插件仓库:
<repositories>和<pluginRepositories>。 - 报告插件:
<reporting>中的配置。
通常不会被继承或需要特别注意的配置:
- 依赖:
<dependencies>节中的依赖本身是会被继承的。但最佳实践是,公共依赖应该放在<dependencyManagement>中声明,而非直接放在<dependencies>里。直接放在<dependencies>中的依赖,会强制传递给所有子模块,这可能不是你想要的效果。 - 构建配置:
<build>中的<resources>,<plugins>等配置会被继承。但子模块可以通过重新定义来覆盖或扩展。 <parent>元素:显然,这个只能用于子模块指向其父模块,不能反过来。
注意:一个常见的误区是认为
<dependencyManagement>里的依赖会自动添加到子模块的类路径。不会!它只是一个“版本和范围的定义清单”。子模块必须在自己的<dependencies>里声明需要的依赖(可以省略版本号),才会真正引入。
3. 核心细节解析与实操要点
3.1<dependencyManagement>:依赖管理的皇冠
这是父子POM继承中最强大、也最容易被误用的特性。它的核心思想是:在父POM中集中定义所有可能用到的依赖及其版本、排除项、作用域;在子POM中,只需声明“我需要这个依赖”,而无需指定版本。
父POM配置示例:
<project> ... <dependencyManagement> <dependencies> <!-- 定义Spring Boot的BOM,统一管理其生态版本 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>2.7.18</version> <type>pom</type> <scope>import</scope> </dependency> <!-- 定义项目自定义的公共依赖 --> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> <version>3.12.0</version> </dependency> <dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>32.1.3-jre</version> </dependency> </dependencies> </dependencyManagement> </project>子POM使用示例:
<project> <parent>...</parent> <artifactId>my-service</artifactId> <dependencies> <!-- 使用父POM中管理的依赖,无需写版本 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <!-- 版本从spring-boot-dependencies中继承 --> </dependency> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> <!-- 版本从父POM的dependencyManagement中继承 --> </dependency> <!-- 子模块特有的依赖,如果版本不在父POM管理中,则需要自己声明版本 --> <dependency> <groupId>com.special</groupId> <artifactId>special-library</artifactId> <version>1.2.3</version> </dependency> </dependencies> </project>为什么这是最佳实践?
- 版本一致性:确保所有模块使用的第三方库版本完全相同,避免因版本差异导致的诡异Bug。
- 简化子POM:子模块的依赖列表变得非常干净,只关注业务需要的库,而不关心版本号。
- 升级便捷:升级某个公共库(比如修复安全漏洞),只需在父POM的
<dependencyManagement>中修改一次版本号,所有子模块在下一次构建时自动生效。 - 避免依赖地狱:明确声明了每个依赖的版本,解决了Maven传递依赖可能带来的版本冲突问题。
实操心得:对于Spring Boot项目,强烈建议在父POM中通过<scope>import</scope>导入官方的spring-boot-dependencies的BOM(Bill of Materials)。这样,绝大多数Spring生态的依赖版本就由Spring Boot团队帮你管理好了,你只需要在子模块中直接引用spring-boot-starter-*而无需写版本,这是最省心、最规范的做法。
3.2<pluginManagement>:统一构建行为
与依赖管理类似,插件管理用于统一项目中所有Maven插件(如编译器插件、打包插件、代码风格检查插件)的版本和基础配置。
父POM配置示例:
<project> ... <build> <pluginManagement> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.11.0</version> <configuration> <source>11</source> <target>11</target> <encoding>UTF-8</encoding> </configuration> </plugin> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <version>2.7.18</version> <configuration> <mainClass>com.example.Application</mainClass> </configuration> </plugin> </plugins> </pluginManagement> </build> </project>子POM使用示例:
<project> <parent>...</parent> <artifactId>my-service</artifactId> <build> <plugins> <!-- 引用父POM中管理的插件,无需写版本和重复配置 --> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> </plugin> <!-- 如果子模块是Spring Boot可执行应用,则引入boot插件 --> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>这样做的好处是,所有子模块的Java编译版本、源码编码等都被强制统一了。如果你想升级插件版本或者修改某个通用配置,只需要在父POM中改动一处。
3.3 属性继承与覆盖:灵活的参数化
<properties>节是存放项目常量、版本号的好地方。这些属性会被所有子模块继承,并可以在POM的任何地方通过${property.name}的形式引用。
父POM配置示例:
<project> ... <properties> <java.version>11</java.version> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <spring-boot.version>2.7.18</spring-boot.version> <my.custom.version>1.0.0-SNAPSHOT</my.custom.version> </properties> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>${spring-boot.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <build> <pluginManagement> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.11.0</version> <configuration> <source>${java.version}</source> <target>${java.version}</target> </configuration> </plugin> </plugins> </pluginManagement> </build> </project>子POM覆盖示例:
<project> <parent>...</parent> <artifactId>legacy-module</artifactId> <properties> <!-- 覆盖父POM中的java.version属性,此模块必须用Java 8 --> <java.version>1.8</java.version> </properties> </project>在这个例子中,legacy-module模块的编译版本会变成Java 8,而其他继承父POM且未覆盖该属性的模块,仍然使用Java 11。这提供了极大的灵活性,允许你在统一管理的大框架下,为特殊模块做定制化配置。
4. 实操过程与核心环节实现
4.1 项目结构搭建标准流程
假设我们要创建一个名为enterprise-platform的多模块项目,包含一个父模块和三个子模块(common-core,user-service,order-service)。
第一步:创建项目根目录和父POM
- 新建文件夹
enterprise-platform。 - 在该文件夹内创建
pom.xml,这就是父POM。
父POM (enterprise-platform/pom.xml) 内容骨架:
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <!-- 项目坐标 --> <groupId>com.example.enterprise</groupId> <artifactId>enterprise-platform</artifactId> <version>1.0.0-SNAPSHOT</version> <packaging>pom</packaging> <!-- 关键! --> <!-- 模块声明 --> <modules> <module>common-core</module> <module>user-service</module> <module>order-service</module> </modules> <!-- 属性定义 --> <properties> <java.version>11</java.version> <maven.compiler.source>${java.version}</maven.compiler.source> <maven.compiler.target>${java.version}</maven.compiler.target> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <spring-boot.version>2.7.18</spring-boot.version> <lombok.version>1.18.30</lombok.version> </properties> <!-- 依赖管理 --> <dependencyManagement> <dependencies> <!-- 导入Spring Boot BOM --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>${spring-boot.version}</version> <type>pom</type> <scope>import</scope> </dependency> <!-- 管理公共工具依赖 --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>${lombok.version}</version> <scope>provided</scope> </dependency> </dependencies> </dependencyManagement> <!-- 构建配置管理 --> <build> <pluginManagement> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.11.0</version> </plugin> </plugins> </pluginManagement> </build> </project>第二步:创建子模块
- 在
enterprise-platform目录下,创建子模块文件夹:common-core,user-service,order-service。 - 在每个子模块文件夹内,创建它们自己的
pom.xml。
子模块POM示例 (enterprise-platform/common-core/pom.xml):
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <!-- 声明父模块 --> <parent> <groupId>com.example.enterprise</groupId> <artifactId>enterprise-platform</artifactId> <version>1.0.0-SNAPSHOT</version> <!-- 如果父POM不在上一级目录,需要用<relativePath>指定 --> <!-- <relativePath>../pom.xml</relativePath> --> </parent> <!-- 子模块自己的坐标,继承父的groupId和version --> <artifactId>common-core</artifactId> <!-- packaging 默认为 jar,符合common-core的用途 --> <dependencies> <!-- 使用父POM管理的依赖,无需版本 --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <!-- scope从父POM的dependencyManagement中继承为provided --> </dependency> <!-- 子模块特有的依赖 --> <dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>32.1.3-jre</version> <!-- 父POM未管理,需自己指定 --> </dependency> </dependencies> </project>第三步:验证与构建
- 打开终端,进入项目根目录
enterprise-platform。 - 运行
mvn clean compile。- Maven会首先读取父POM,然后根据
<modules>列表依次进入每个子模块目录进行构建。 - 在构建子模块时,Maven会合并父子POM,解析出最终的“有效POM”。
- 你会看到Maven成功下载了父POM中管理的依赖(如Lombok),并使用了指定的编译器版本进行编译。
- Maven会首先读取父POM,然后根据
4.2 子模块间的依赖引用
在多模块项目中,子模块之间经常需要相互依赖。例如,user-service和order-service都可能依赖common-core。
在user-service/pom.xml中声明对common-core的依赖:
<project> <parent>...</parent> <artifactId>user-service</artifactId> <dependencies> <!-- 依赖同一个父项目下的兄弟模块 --> <dependency> <groupId>com.example.enterprise</groupId> <!-- 继承自父POM --> <artifactId>common-core</artifactId> <version>${project.version}</version> <!-- 使用当前项目版本 --> </dependency> <!-- 其他依赖 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> </dependencies> <build> <plugins> <!-- 因为这是一个可执行的Spring Boot应用,所以需要引入插件 --> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>关键点:
- 依赖兄弟模块时,
<groupId>和<version>通常与父模块一致,可以使用Maven内置属性${project.version}来引用当前项目的版本,这样当父POM版本升级时,所有模块间依赖版本会自动同步。 - 由于
common-core也是一个Maven模块,当你对根目录执行mvn install后,它会被安装到本地仓库。这样user-service在构建时就能从本地仓库找到它。 - 这种模块间依赖是Maven能够正确解析构建顺序(先构建被依赖的模块)的基础。
4.3 使用Maven命令与IDE集成
命令行操作:
- 构建整个项目:在根目录执行
mvn clean install。这会按顺序构建所有模块并安装到本地仓库。 - 构建单个模块:进入特定子模块目录,如
cd user-service,然后执行mvn clean compile。Maven会自动定位父POM并合并配置。 - 跳过测试:使用
-DskipTests参数,如mvn clean install -DskipTests。 - 查看有效POM:在任意模块目录下执行
mvn help:effective-pom。这个命令会输出合并了所有父POM、超级POM(Maven默认配置)和当前POM后的最终XML。这是排查配置问题的终极利器,当继承关系复杂或配置不生效时,一定要先看有效POM。
IDE集成(以IntelliJ IDEA为例):
- 导入项目:直接打开包含父POM的根目录(
enterprise-platform)。IDEA会自动识别为Maven多模块项目,并在侧边栏以树形结构展示所有模块。 - 配置生效:IDEA会正确读取继承关系。在子模块的
pom.xml中,你会看到从父POM继承来的依赖(通常显示为灰色或带有特殊图标),并且这些依赖的版本号是锁定的。 - 运行与调试:你可以右键点击某个子模块(如
user-service),选择“Run 'user-service'”,IDEA会使用合并后的有效POM配置来运行这个Spring Boot应用。 - 依赖图:使用IDEA的Maven工具窗口,可以可视化查看模块间的依赖关系,非常直观。
实操心得:在团队协作中,务必确保所有成员都使用相同版本的Maven(至少是3.x系列)和相同的JDK版本。因为父子POM的合并逻辑、属性解析等可能因Maven版本有细微差异。将Maven Wrapper(mvnw)纳入版本控制是一个好习惯,它能保证构建环境的一致性。
5. 常见问题与排查技巧实录
即使理解了原理,在实际操作中依然会遇到各种“坑”。下面是我在多年实践中总结的一些典型问题及其解决方法。
5.1 依赖找不到或版本冲突
问题现象:在子模块中运行mvn compile或IDE中报错,提示Could not find artifact或ClassNotFoundException/NoClassDefFoundError。
排查步骤:
- 检查父POM是否已安装:子模块构建依赖于父POM的
pom.xml文件。如果父POM尚未被安装到本地仓库(通过mvn install),或者你刚刚修改了父POM但未重新安装,子模块就会找不到依赖。解决方法:先在项目根目录执行mvn clean install。 - 检查
dependencyManagement使用是否正确:确认子模块中声明的依赖,其groupId和artifactId是否与父POM<dependencyManagement>中定义的完全一致(包括大小写)。同时,子模块依赖声明中不能有<version>标签,否则它会覆盖父POM中的管理,如果这个版本号写错了或者不存在,就会报错。 - 查看有效POM:在出问题的子模块目录下运行
mvn help:effective-pom > effective.xml,然后打开生成的effective.xml文件,搜索你缺失的依赖。看看它最终被解析成了什么版本、什么作用域。很多时候问题就出在这里——可能继承来的依赖被排除了,或者作用域是test/provided,导致运行时找不到。 - 检查依赖范围:如果依赖在
<dependencyManagement>中定义了<scope>provided</scope>(如Lombok),那么它不会被打进子模块的jar包中。如果另一个模块依赖了这个jar包并需要这个库,就会报错。需要根据实际情况调整作用域。
5.2 配置不生效或被子模块覆盖
问题现象:在父POM中定义的插件配置、资源过滤规则等在子模块中似乎没起作用。
排查步骤:
- 理解合并规则:记住,子POM中的配置会覆盖父POM中的同名配置,对于列表则是追加。如果你在子POM的
<build>里重新定义了<plugins>,那么父POM<pluginManagement>里的配置可能因为子POM没有引用而失效。解决方法:在子POM的<plugins>里,需要通过<plugin>标签声明要使用父POM管理的插件,这样配置才会生效。 - 检查
<pluginManagement>vs<plugins>:父POM中统一管理插件版本和基础配置,应该放在<pluginManagement>里。子POM需要在<plugins>里引用这些插件。如果父POM把插件直接放在<plugins>里,那么所有子模块都会强制应用这个插件及其执行阶段,这可能不是你想要的效果。 - 再次查看有效POM:这是最可靠的诊断方法。对比有效POM和你期望的配置,差异一目了然。
5.3 多级继承与相对路径问题
问题现象:项目结构非常深,有祖父模块、父模块、子模块的多级继承,构建时Maven报错找不到父POM。
原因与解决:在子POM的<parent>元素中,如果父POM不在标准的上一级目录(../pom.xml),Maven可能无法定位。这时需要使用<relativePath>元素明确指定路径。
<parent> <groupId>com.example</groupId> <artifactId>super-parent</artifactId> <version>1.0</version> <!-- 指定父POM的相对路径 --> <relativePath>../../super-parent/pom.xml</relativePath> </parent>实操心得:尽量避免超过两级的深层继承(例如 祖POM -> 父POM -> 子模块)。这会让项目结构变得复杂,配置难以追踪。通常,一个顶层的父POM(聚合模块)管理所有公共配置,其下直接是各个业务子模块,这样的扁平结构是最清晰、最易维护的。如果确实需要多级,务必使用<relativePath>并仔细规划目录结构。
5.4 常见问题速查表
| 问题现象 | 可能原因 | 排查与解决思路 |
|---|---|---|
Could not find artifact ... | 1. 父POM未安装到本地仓库。 2. 子模块依赖的 groupId/artifactId与父POM管理的不一致。3. 仓库网络问题。 | 1. 在根目录执行mvn install。2. 仔细核对依赖坐标。 3. 检查Maven镜像配置(如阿里云镜像),运行 mvn -U clean compile强制更新。 |
| 依赖版本不是预期的 | 1. 子模块依赖声明中误写了<version>,覆盖了父POM管理。2. 传递依赖引入了其他版本,发生冲突。 | 1. 删除子模块依赖中的<version>标签。2. 运行 mvn dependency:tree查看依赖树,在父POM的<dependencyManagement>中明确指定冲突依赖的版本。 |
| 插件配置不生效 | 1. 父POM配置在<pluginManagement>中,但子模块未在<plugins>里引用该插件。2. 子模块用自己的配置完全覆盖了父POM配置。 | 1. 在子模块<plugins>中添加对该插件的引用(不带版本)。2. 检查子模块POM,移除或修改冲突的配置。使用 mvn help:effective-pom对比。 |
| 构建顺序错误 | 模块间存在循环依赖。A依赖B,B又依赖A。 | 这是严重的设计问题。必须重构代码,打破循环依赖。通常可以提取公共部分到第三个模块C,让A和B都依赖C。 |
| IDEA中依赖标红 | 1. IDEA的Maven项目模型未正确刷新。 2. 本地仓库索引损坏。 | 1. 点击IDEA右侧Maven工具窗口的刷新按钮(Reimport All Maven Projects)。 2. 尝试删除本地仓库中对应的依赖目录,然后重新刷新。 |
5.5 高级技巧:使用importscope管理第三方BOM
对于超大型项目或深度使用某个框架(如Spring Cloud),依赖数量极多。除了Spring Boot的BOM,你还可以导入其他官方或自定义的BOM。
<dependencyManagement> <dependencies> <!-- 导入Spring Boot BOM --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>${spring-boot.version}</version> <type>pom</type> <scope>import</scope> </dependency> <!-- 导入Spring Cloud BOM --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>2021.0.8</version> <type>pom</type> <scope>import</scope> </dependency> <!-- 导入公司内部平台的BOM --> <dependency> <groupId>com.mycompany.platform</groupId> <artifactId>platform-bom</artifactId> <version>2.0.0</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>importscope的精髓:它将指定BOM文件中<dependencyManagement>的内容全部导入到当前POM的<dependencyManagement>中。这样,你的子模块就可以直接使用这些BOM中定义的所有依赖,而无需在你的父POM中逐一列出。这是管理超大型依赖集的终极武器。
最后的小建议:定期运行mvn versions:display-dependency-updates和mvn versions:display-plugin-updates命令,可以检查项目中所有依赖和插件是否有新版本可用,这对于保持项目依赖的健康度和安全性至关重要。在父子模块结构中,只需要在父POM目录下运行即可扫描所有模块。