背景说明
在使用Maven多模块结构工程时,版本管理是一件很繁琐且容易出错的事情。每次升级版本号都要手动调整或者通过mvn versions:set -DnewVerion=xx
命令去更改每一个子模块的版本号,非常的不方便,而且会改动所有的模块,出现如下效果:
解决方法
其实Maven已经提供了这种CI版本的管理方式,下面来介绍一下具体使用方法。
Maven官方文档说:自 Maven 3.5.0-beta-1 开始,可以使用 ${revision}, ${sha1} and/or ${changelist} 这样的变量作为版本占位符。
即在maven多模块项目中,可配合插件flatten-maven-plugin
及${revision}
属性来实现全局版本统一管理。
环境说明
Maven Version:Apache Maven 3.5.0-beta-1及以上版本
Maven Plugin:flatten-maven-plugin
IDE: IntelliJ IDEA 2021.3
JDK: 1.8.0_301
POM文件:使用占位符${revision}
注意事项
① 只能命名成revision
,不可以更改成其他命名;
② Idea下使用${revision}
定义Parent版本时会提示错误“Reports that usage of properties in modules parent definition is prohibited”
,但并不影响使用,只是Idea不支持这种写法而已,升级IDea版本也可以解决 【可忽略】。
代码示例
父模块配置
在properties标签中定义revision标签:
<project>
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.4.RELEASE</version>
<relativePath/>
</parent>
<groupId>org.sssss.maven</groupId>
<artifactId>sssss-parent</artifactId>
<version>${revision}</version>
<packaging>pom</packaging>
<properties>
<!-- 全局版本控制,如果要修改版本号,修改此处即可-->
<revision>1.0.0-SNAPSHOT</revision>
</properties>
<modules>
<module>sssss-child1</module>
...
</modules>
<build>
<plugins>
<!-- 添加flatten-maven-plugin插件 -->
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>flatten-maven-plugin</artifactId>
<version>1.5.0</version>
<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>
<inherited>true</inherited>
<configuration>
<!-- 避免IDE将 .flattened-pom.xml 自动识别为功能模块 -->
<updatePomFile>true</updatePomFile>
<flattenMode>resolveCiFriendliesOnly</flattenMode>
</configuration>
</plugin>
</plugins>
</build>
</project>
关键点:
① 父子模块需遵循父子目录层次;
② 在父模块中引入插件flatten-maven-plugin
;
③ 修改.gitignore文件,增加一行.flattened-pom.xml
;
④ 不可混合使用${revision}
和明确字符串版本号,若出现父子模块版本号混合使用${revision}和明确字符串形式如1.0.0.-SNAPSHOT,在mvn package会出现类似如下错误:
[FATAL] Non-resolvable parent POM for org.sssss.maven:child1:[unknown-version]:
Could not find artifact org.sssss.maven:sssss-parent:pom:1.0.0-SNAPSHOT and ‘parent.relativePath’ points at wrong local POM @ line 5, column 13
关于子模块中parent.relativePath使用:
- 默认值,不设置relativePath即为默认值,等价于
<relativePath>../pom.xml</relativePath>
,即遵循父子目录层次- 即优先查找上层目录…/pom.xml
- 然后查找本地仓库
- 最后查找远程仓库
- 推荐自定义的开发项目遵循此种方式(即父子模块需遵循父子目录层次,且保持parent.relativePath的默认值)
- 空值,即跳过本地文件目录查找
- 直接查找本地仓库
- 最后查找远程仓库
- 适用于父依赖为第三方公有仓库中的依赖,如spring-boot-starter-parent
- 其他值,可根据目录层次自行定义(推荐使用相对目录层次),如
<relativePath>../module-1/pom.xml</relativePath>
子模块配置
子模块可以直接使用${revision}指定父模块的版本:
<project>
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.sssss.maven</groupId>
<artifactId>sssss-parent</artifactId>
<version>${revision}</version>
<relativePath>../pom.xml</relativePath> <!-- 可忽略 -->
</parent>
<artifactId>sssss-child1</artifactId>
<packaging>jar</packaging>
</project>
子模块依赖
多模块工程结构下,会有子模块相互依赖的情况,使用${revision}
会导致构建失败,应该使用${project.version}
来定义依赖 (同父工程下的依赖) 的版本,请勿使用${parent.version}
。
<project>
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.sssss.maven</groupId>
<artifactId>sssss-parent</artifactId>
<version>${revision}</version>
<relativePath>../pom.xml</relativePath> <!-- 可忽略 -->
</parent>
<artifactId>sssss-child2</artifactId>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>org.sssss.maven</groupId>
<artifactId>child1</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
install / depoy
执行install/deploy后,会将该模块的pom文件中的${revision}替换为实际的版本,每个模块下都会生成一个.flattened-pom.xml
文件。
基于以上操作,每次版本号变更,只需要修改父模块POM文件中的revision
即可。还可以用另一种动态添加参数的方式来指定版本:
mvn clean install -Drevision=1.0.0-SNAPSHOT # -D代表设置环境变量
参考文章
maven-ci-friendly
flatten-maven-plugin
spring-boot-project
maven-relativepath
Maven多模块结构下版本管理的正确姿势