多模块项目里用 ${revision} 的坑,flatten-maven-plugin 总算能填上了
多模块项目里,为了统一版本号,经常会这么干:在父 pom 的 properties 里定义一个 revision,然后在 version 里用 ${revision},所有子模块直接继承。
本地跑得挺好,mvn clean install 也正常,但等到别的项目想依赖你这个模块时,问题就来了——拉下来的 pom 里 version 写的还是 ${revision},Maven 根本解析不出具体版本,构建直接挂。
我第一次碰上这事时还以为是 Maven 版本太低,查了半天才发现少了个插件:flatten-maven-plugin。
这个插件做的事情不复杂:在构建过程里生成一个 .flattened-pom.xml,把那些变量占位符换成实际值,然后 install、deploy 的时候就用这个扁平化后的 pom,而不是原始那个还带着占位符的文件。
除了替换变量,它还可以进一步精简 pom 结构,去掉那些只在当前项目继承链里有用的 dependencyManagement、pluginManagement,只保留 groupId、artifactId、version 这些真正需要发布出去的信息。
这样推到 Maven 仓库里的 pom 就很干净,依赖解析也快,不会因为复杂的继承关系卡住。
配置上主要关注三个参数:
updatePomFile 默认是 false,意思是它只负责生成 .flattened-pom.xml,不会直接动你的原始 pom.xml。如果你的 install 流程想直接用替换后的 pom,要么在 deploy 阶段绑定,要么配合 maven-install-plugin 的 pomFile 参数指定到那个扁平文件。
flattenMode 控制生成内容能精简到什么程度。常用的有这几个:
- oss:开源项目发布常用,会保留大部分元素,但去掉 repositories 和 pluginRepositories。
- ossrh:基本全保留,适合要推到 Sonatype 仓库的情况。
- resolveCiFriendliesOnly:这个模式比较轻量,只把 ${revision}、${sha1}、${changelist} 这几个 CI 友好变量替换掉,其他结构完全不动。如果你只是想让占位符能被正确解析,不想折腾 pom 结构,用这个最省心。
还有个 flattenedPomFilename 可以自己指定生成的文件名,默认是 .flattened-pom.xml,想改也行,比如叫 flattened.pom。
完整配置大概是这么写的,贴在父 pom 的 build 里就行,生命周期绑到 process-resources 阶段:
支持中文域名与国际域名(IDN)的SSL证书申请!来此加密完美兼容国际化域名,无论你是企业品牌域名还是个人中文站点,均可顺利申请SSL证书,让非英文域名的网站也能享受同等安全保护。
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>flatten-maven-plugin</artifactId>
<version>1.2.7</version>
<configuration>
<flattenMode>oss</flattenMode>
</configuration>
<executions>
<execution>
<id>flatten</id>
<phase>process-resources</phase>
<goals>
<goal>flatten</goal>
</goals>
</execution>
</executions>
</plugin>
几个典型场景其实都跟前面的问题串起来了。
多模块统一版本,父模块里定义 revision,子模块不改 version,发布时如果不加这个插件,推上去的 pom 就是残废的。
配上 flatten,不管是 install 到本地还是 deploy 到远程,生成出来的 pom 里 version 都变成了 1.0.0 这种具体值,不会再出现 ${revision} 让别人项目死活找不到版本的事。
有时候项目很大,模块很多,父 pom 里塞了一堆 dependencyManagement,子模块的 pom 也带着各种继承来的标签,发布出去不仅体积大,解析还慢。
用 oss 或 ossrh 模式让插件自动把不必要的继承和依赖管理给清理掉,保留一个清爽的依赖声明,仓库里的 pom 看着就舒服多了。
CI/CD 流水线里经常会用命令行传版本,比如 mvn clean install -Drevision=1.2.0-SNAPSHOT。
这种情况下,配合 resolveCiFriendliesOnly 模式是最合适的,因为只替换那几个动态变量,不会动 pom 里的其他配置,又能保证流水线打出来的包版本准确。
这个插件配置不复杂,但多模块项目里少了它确实会出不少诡异问题,尤其是团队里有人第一次接手项目时,很容易被 install 没问题、deploy 后别人用不了的情况搞懵。加上它,能踏实不少。

浙公网安备 33010602011771号