本文目录导读:

Maven聚合父工程(通常称为pom打包方式的父项目)是管理多模块项目的核心方式,它主要解决两个问题:批量构建(聚合)和统一依赖管理(继承)。
以下是关于如何创建和管理 Maven 聚合父工程与子模块的详细指南。
核心概念
- 聚合(Aggregation):
- 父工程的
pom.xml中通过<modules>标签声明子模块。 - 作用:当你在父工程目录执行
mvn clean install时,Maven 会自动按照依赖关系顺序构建所有子模块。
- 父工程的
- 继承(Inheritance):
- 父工程的
pom.xml中定义公共配置(如依赖版本、插件、仓库等)。 - 子模块的
pom.xml通过<parent>标签声明继承自哪个父工程。 - 作用:消除重复配置,统一项目规范。
- 父工程的
目录结构示例
假设项目名为 my-project,包含三个子模块:common、service、web。
my-project/ # 根目录(通常就是父工程)
├── pom.xml # 父工程的 POM,packaging 为 pom
├── my-project-common/ # 子模块1
│ └── pom.xml
├── my-project-service/ # 子模块2
│ └── pom.xml
└── my-project-web/ # 子模块3
└── pom.xml
父工程 pom.xml 配置详解
父工程的 packaging 必须为 pom,这是聚合和管理子模块的前提。
<?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</groupId>
<artifactId>my-project</artifactId>
<version>1.0.0-SNAPSHOT</version>
<!-- 关键点:打包方式必须是 pom -->
<packaging>pom</packaging>
<name>My Project Parent</name>
<description>父工程,负责管理子模块和统一依赖</description>
<!-- 1. 声明子模块(聚合) -->
<modules>
<module>my-project-common</module>
<module>my-project-service</module>
<module>my-project-web</module>
<!-- 注意:module 标签里放的是子模块的目录名(相对路径) -->
</modules>
<!-- 2. 统一属性管理 -->
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<!-- 统一管理第三方依赖版本 -->
<spring.boot.version>3.2.0</spring.boot.version>
<lombok.version>1.18.30</lombok.version>
<mysql.connector.version>8.0.33</mysql.connector.version>
</properties>
<!-- 3. 依赖管理(关键:<dependencyManagement>) -->
<!-- 这里只声明版本,不实际引入依赖 -->
<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>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.connector.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
<!-- 4. 所有子模块都会继承的公共依赖(较少使用,一般放日志、lombok等) -->
<dependencies>
<!-- 所有子模块都需要 SLF4J -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>2.0.9</version>
</dependency>
</dependencies>
<!-- 5. 统一插件管理 -->
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring.boot.version}</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.11.0</version>
<configuration>
<source>${maven.compiler.source}</source>
<target>${maven.compiler.target}</target>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
子模块 pom.xml 配置详解
以 my-project-service 为例:
<?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>
<!-- 1. 声明父工程(继承) -->
<parent>
<groupId>com.example</groupId>
<artifactId>my-project</artifactId>
<version>1.0.0-SNAPSHOT</version>
<!-- 相对路径:指向父工程的 pom.xml 文件 -->
<relativePath>../pom.xml</relativePath>
</parent>
<!-- 2. 子模块自己的坐标 -->
<!-- 注意:通常省略 groupId 和 version,它们会从父工程继承 -->
<artifactId>my-project-service</artifactId>
<!-- packaging 默认为 jar,如果是 web 模块可以用 war -->
<packaging>jar</packaging>
<name>My Project Service</name>
<description>业务逻辑层模块</description>
<!-- 3. 子模块自己的依赖 -->
<dependencies>
<!-- 依赖同一项目的其他子模块 -->
<dependency>
<groupId>com.example</groupId>
<artifactId>my-project-common</artifactId>
<!-- 注意:这里不需要写 version,因为父工程已管理 -->
</dependency>
<!-- 使用父工程管理的依赖,只需写 groupId 和 artifactId -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<!-- 版本号由父工程的 spring-boot-dependencies 管理 -->
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<!-- 版本由父工程的 <dependencyManagement> 管理 -->
</dependency>
</dependencies>
</project>
dependencyManagement 与 dependencies 的区别
| 特性 | <dependencies> (在父工程中) |
<dependencyManagement> (在父工程中) |
|---|---|---|
| 作用 | 所有继承的子模块强制引入该依赖 | 声明依赖的版本号,子模块按需引入 |
| 是否被子模块继承 | 是,子模块自动拥有该依赖 | 否,子模块需要显式声明 dependency |
| 典型场景 | 公共日志、Lombok、测试框架等 | Spring Boot 版本、Jackson 版本等 |
| 子模块声明时 | 无需再次声明 | 必须声明,但可以省略 version |
建议:父工程中尽量使用 <dependencyManagement> 管理版本,避免在父工程中直接放过多 <dependencies>,防止子模块被迫引入不需要的库。
常见问题与最佳实践
<relativePath> 要写吗?
- 推荐写:
<relativePath>../pom.xml</relativePath>可以提高构建的确定性。 - 可选但建议:如果不写,Maven 会先尝试从本地仓库、远程仓库查找父 POM,如果你本地的父 POM 还没有安装到仓库,构建就会失败。
子模块可以不被父工程包含吗?
- 可以,父工程只是通过
<modules>管理你需要一起构建的模块,其他项目可以通过坐标直接引用你的子模块。
版本号冲突如何处理?
- 原则:在父工程的
<dependencyManagement>中统一定义所有关键依赖的版本,子模块中尽量避免写版本号。 - 如果有必要在子模块中覆盖版本,可以在子模块的
<dependency>中明确指定version。
模块间依赖顺序
service依赖common,Maven 构建时会自动先构建common,再构建service,你不需要担心顺序。
父工程本身不包含业务代码
- 父工程的
src目录通常可以删除,它只负责管理配置。packaging为pom的项目不需要src/main/java。
构建命令
-
构建整个项目(在父工程目录下执行):
mvn clean install
-
只构建某个子模块及其依赖(在父工程目录下执行):
mvn clean install -pl my-project-service -am
-pl:指定模块-am:also make,表示同时构建该模块依赖的其他模块
-
跳过测试构建:
mvn clean install -DskipTests
通过合理的父工程设计,你可以实现:
- 一键全量构建。
- 零版本号冲突。
- 统一的开发规范(编译器版本、编码格式)。