Maven 多模块项目最佳实践
多模块项目把单体工程拆分为职责独立的模块,配合继承与聚合统一管理。本节聚焦多模块的版本管理方案:${revision}、flatten 插件与 Maven 4 的原生支持。
多模块结构设计
project/ 聚合根(packaging=pom)
├── pom.xml 父 POM:聚合 + 继承 + 版本管理
├── common/ 通用基础模块(工具、常量、DTO)
├── service/ 业务服务模块
└── web/ 接口/启动模块设计原则:
- 聚合根:packaging 为
pom,声明<modules> - 父 POM:承载
<properties>、<dependencyManagement>、公共<dependencies>、公共<pluginManagement> - 模块职责单一:common 不依赖业务模块,service 依赖 common,web 依赖 service
- 避免循环依赖:模块间依赖只能单向,构建才能按拓扑序进行
统一版本管理演进
多模块最大的痛点是版本:升级版本时,若每个模块各写各的 version,漏改一个就版本不一致。
传统方式:继承 + 手写版本
每个子模块 POM 都要写 <version>,与父 POM 保持一致。升级版本要改 N 个文件,易错。
${revision}:一处定义,全局生效
父 POM 用 ${revision} 作为版本占位符,子模块省略 version 自动继承:
xml
<!-- 父 POM -->
<project>
<groupId>com.example</groupId>
<artifactId>parent-project</artifactId>
<version>${revision}</version>
<packaging>pom</packaging>
<modules>
<module>common</module>
<module>service</module>
<module>web</module>
</modules>
<properties>
<revision>1.0.0</revision>
</properties>
</project>xml
<!-- common/pom.xml:无 version,自动使用 ${revision} -->
<project>
<parent>
<groupId>com.example</groupId>
<artifactId>parent-project</artifactId>
<version>${revision}</version>
</parent>
<artifactId>common</artifactId>
</project>bash
# 覆盖版本号构建(CI/CD 场景)
mvn clean install -Drevision=1.0.0-SNAPSHOT注意:父 POM 的 <version> 必须写 ${revision},而不是字面版本号,否则子模块无法正确解析父版本。
flatten-maven-plugin:解决 ${revision} 残留
直接使用 ${revision} 有一个缺陷:安装/部署时生成的 POM 中仍保留 ${revision} 占位符,其他项目引用该构件时版本解析失败。
flatten-maven-plugin 在构建时把 POM 展平,将占位符替换为实际版本:
xml
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>flatten-maven-plugin</artifactId>
<version>1.6.0</version>
<configuration>
<updatePomFile>true</updatePomFile>
<flattenMode>resolveCiFriendliesOnly</flattenMode>
</configuration>
<executions>
<execution>
<id>flatten</id>
<phase>process-resources</phase>
<goals><goal>flatten</goal></goals>
</execution>
<execution>
<id>flatten.clean</id>
<phase>clean</phase>
<goals><goal>clean</goal></goals>
</execution>
</executions>
</plugin>
</plugins>
</build>工作流程:
源码 POM(含 ${revision})→ flatten 展平 → 安装/部署的 POM(实际版本号).flattened-pom.xml 是展平产物,用于安装到本地仓库/发布到远程仓库。
Maven 4 原生多模块
Maven 4(4.0 起)把版本管理进一步简化,核心变化:
1. .mvn/maven.properties 集中属性
版本与构建属性统一放到 .mvn/maven.properties,无需在每个 POM 重复:
properties
# .mvn/maven.properties
project.version=1.0.0
maven.compiler.source=21
maven.compiler.target=21
project.build.sourceEncoding=UTF-82. 父 POM 引用文件属性
xml
<project>
<groupId>com.example</groupId>
<artifactId>parent-project</artifactId>
<version>${project.version}</version>
<packaging>pom</packaging>
<modules>
<module>common</module>
<module>web</module>
</modules>
</project>3. 子模块无需父 version
Maven 4 中子模块 <parent> 可以省略 version,自动从 .mvn/maven.properties 继承:
xml
<!-- common/pom.xml(Maven 4) -->
<project>
<parent>
<groupId>com.example</groupId>
<artifactId>parent-project</artifactId>
</parent>
<artifactId>common</artifactId>
</project>4. 版本升级只需改一个文件
bash
# 改 .mvn/maven.properties 中 project.version 即可
mvn clean deployMaven 3 与 Maven 4 对比
| 对比项 | Maven 3(${revision}) | Maven 4 原生 |
|---|---|---|
| 版本定义位置 | 父 POM <properties> | .mvn/maven.properties |
| 修改版本 | 改 POM | 改一个属性文件 |
| flatten 插件 | 必需 | 可选(内置展平) |
| 子模块父引用 | 必须写 version | version 可省略 |
| CI 版本注入 | 手动 -Drevision | .mvn/maven.config 自动 |
| 最低版本 | Maven 3.5+ | Maven 4.0+ |
多模块常见问题
- 构建某个模块及依赖模块?
mvn install -pl web -am(-pl 指定模块,-am 同时构建其依赖模块)。 - 跳过兄弟模块?
mvn install -pl web -amd(-amd 构建依赖 web 的模块)。 - 模块间依赖版本解析失败? 检查父 POM
<version>是否用了${revision}、flatten 插件是否配置、是否先install过公共模块。 - 打包产物路径? 默认各模块
target/下;-DfinalName或<finalName>统一产物名。 - 并行构建?
mvn install -T 4(4 线程并行),注意依赖关系由 Maven 自动处理。