核心概念与区别
首先,我们先明确两者的本质定位,这是理解区别的关键:
| 特性 | 核心定位 | 解决的核心问题 | 作用阶段 |
|---|---|---|---|
| Maven CI Friendly Versions | Maven 原生特性(3.5.0+) | 允许在 POM 中使用 ${revision}、${sha1}、${changelist} 等占位符定义版本,无需硬编码 |
构建时(Maven 解析 POM 阶段) |
| flatten-maven-plugin | Maven 插件 | 解决 CI 友好版本占位符在发布时的 “污染” 问题(发布的 POM 不能包含占位符),同时可扁平化父子 POM 依赖 | 打包 / 发布阶段(generate-resources 或 package) |
简单来说:
- CI Friendly Versions 是 “允许你写占位符”,让版本管理更灵活;
- flatten-maven-plugin 是 “清理占位符”,让发布的 POM 符合规范(纯静态版本)。
1. Maven CI Friendly Versions 示例
核心作用
在项目 POM 中用 ${revision} 统一管理版本,避免多模块项目中重复修改版本号。
示例(多模块项目)
父 POM (pom.xml):
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>parent-project</artifactId>
<!-- 使用占位符代替硬编码版本 -->
<version>${revision}</version>
<packaging>pom</packaging>
<!-- 定义版本占位符的默认值(可选) -->
<properties>
<revision>1.0.0-SNAPSHOT</revision>
</properties>
<modules>
<module>module-a</module>
<module>module-b</module>
</modules>
</project>
子模块 POM (module-a/pom.xml):
<project>
<parent>
<groupId>com.example</groupId>
<artifactId>parent-project</artifactId>
<!-- 子模块直接继承父版本的占位符,无需改自己的版本 -->
<version>${revision}</version>
</parent>
<artifactId>module-a</artifactId>
<!-- 无需重复写 version,自动继承父版本 -->
</project>
使用方式
构建时通过命令行传入实际版本:
# 构建快照版本 mvn clean install -Drevision=1.0.0-SNAPSHOT # 构建发布版本 mvn clean deploy -Drevision=1.0.0
问题点
如果直接用 mvn deploy 发布,发布到仓库的 POM 文件中依然会包含 ${revision} 占位符,其他项目依赖该模块时会解析失败 —— 这就是 flatten-maven-plugin 要解决的问题。
2. flatten-maven-plugin 示例
核心作用
将包含占位符的 “源 POM” 转换为 “扁平化 POM”(静态版本),并将扁平化后的 POM 发布到仓库。
示例(集成到父 POM)
修改上述父 POM,添加插件配置:
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>parent-project</artifactId>
<version>${revision}</version>
<packaging>pom</packaging>
<properties>
<revision>1.0.0-SNAPSHOT</revision>
</properties>
<build>
<plugins>
<!-- 配置 flatten 插件 -->
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>flatten-maven-plugin</artifactId>
<version>1.5.0</version>
<executions>
<!-- 绑定到 generate-resources 阶段,生成扁平化 POM -->
<execution>
<id>flatten</id>
<phase>generate-resources</phase>
<goals>
<goal>flatten</goal>
</goals>
</execution>
<!-- 绑定到 clean 阶段,清理扁平化 POM -->
<execution>
<id>flatten.clean</id>
<phase>clean</phase>
<goals>
<goal>clean</goal>
</goals>
</execution>
</executions>
<configuration>
<!-- 关键:使用 "resolveCiFriendliesOnly" 模式,只替换 CI 占位符 -->
<flattenMode>resolveCiFriendliesOnly</flattenMode>
<!-- 保留源 POM,将扁平化 POM 输出为 .flattened-pom.xml -->
<updatePomFile>true</updatePomFile>
</configuration>
</plugin>
</plugins>
</build>
<modules>
<module>module-a</module>
<module>module-b</module>
</modules>
</project>
执行效果
- 执行
mvn clean install -Drevision=1.0.0后,每个模块的 target 目录下会生成.flattened-pom.xml; - 扁平化后的 POM 中,
${revision}会被替换为实际值1.0.0:<!-- module-a/target/.flattened-pom.xml --> <project> <parent> <groupId>com.example</groupId> <artifactId>parent-project</artifactId> <version>1.0.0</version> <!-- 占位符已替换 --> </parent> <artifactId>module-a</artifactId> <version>1.0.0</version> <!-- 自动填充实际版本 --> </project> - 发布时,Maven 会将
.flattened-pom.xml作为最终 POM 发布到仓库,其他项目依赖时能正常解析版本。
总结
- 核心定位不同:CI Friendly Versions 是 Maven 原生的 “版本占位符机制”,解决版本统一管理问题;flatten-maven-plugin 是插件,解决占位符发布后无法解析的问题。
- 协作关系:两者通常配合使用 —— 先用 CI Friendly Versions 简化版本维护,再用 flatten-maven-plugin 清理占位符以符合发布规范。
- 关键区别:CI Friendly Versions 是 “写” 的层面的优化,flatten-maven-plugin 是 “发布” 层面的修正。
如果没有 CI Friendly Versions,你需要手动修改所有模块的版本号;如果只用 CI Friendly Versions 不用 flatten 插件,发布的 POM 会包含占位符导致依赖失败。