【架构思考】使用 Parent POM 统一配置项目实战
在 Maven Parent POM 的使用过程中,有两个很重要的概念:Project Inheritance
和 Project Aggregation
(见参考一)。这两个技能的灵活使用,可以解决很多实际问题。
- Project Inheritance:可以让子项目继承父项目的配置。
- Project Aggregation:可以将多个子项目聚合起来形成一个父项目。只要 build 一次父项目,就会 trigger build 所有子项目。
话不多说,直接看实战案例:
Project Inheritance 实战1
需求:项目A,项目B,项目C中,各自引入了许多相同的依赖,比如logging,common-utils等,但是版本不尽相同。在很长的一段时间里,各自相安无事,不影响使用。但是,某一次改动中加入了新的依赖且没有恰当地测试,导致项目A在上线时发生依赖冲突而报错。
解决:我们决定对现有的所有项目的依赖版本统一管理,并且,如果以后有新的依赖改动,会执行更为严格的代码审核和测试。
总体思路:新建一个项目 dependency manager ,其中只包含 xml 配置。然后将其在本地 install ,这样其它项目就可以使用了。(或者 upload 到 nexus repository ,然后使用 Jenkins build 其它项目。)
Parent Pom
<project>
<modelVersion>4.0.0</modelVersion>
<!--define parent-->
<groupId>com.mycompany.app</groupId>
<artifactId>my-parnet-pom-app</artifactId>
<version>1.0</version>
<packaging>pom</packaging>
<!--dependency-->
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
</dependencies>
</project>
项目A
<project>
<modelVersion>4.0.0</modelVersion>
<!--include parent-->
<parent>
<groupId>com.mycompany.app</groupId>
<artifactId>my-parnet-pom-app</artifactId>
<version>1.0</version>
</parent>
<!--module a-->
<groupId>com.mycompany.app</groupId>
<artifactId>my-module-a</artifactId>
<version>1.0</version>
<!--dependency-->
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<!--version in parent pom-->
</dependency>
</dependencies>
</project>
Project Inheritance 实战2
需求:我的项目组内部开发了一些公用包 X,Y,Z,用于项目 A,B,C 中。但是,每次上线的时候非常麻烦,需要很多人工步骤:
- 到项目 X 中,在 pom 文件里,去掉snapshot。例如把版本号的从 x.123-snapshot 改成 x.123。
- 到项目 Y,Z 中重复一遍。
- 到项目 A 中,在 pom 文件里,更新 X,Y,Z 的版本号。
- 到项目 B,C 中重复一遍。
(注:A,B,C 的版本号去 snapshot 操作会在 Jenkins Release 时的 Web Portal 进行。)
可以想见,随着项目数量增多,操作会变得越来越复杂,也非常容易出错。
解决:将所有自己开发的项目的版本号统一管理。
思路:基于以上的例子,只需要做一点点改变。即在 child project 中不定义自己的 version 和 groupId ,而是在 parent pom 中统一定义。
项目A
<project>
<modelVersion>4.0.0</modelVersion>
<!--include parent-->
<parent>
<groupId>com.mycompany.app</groupId>
<artifactId>my-parnet-pom-app</artifactId>
<version>1.0</version>
</parent>
<!--module a-->
<artifactId>my-module-a</artifactId>
<!--groupId in parent pom-->
<!--version in parent pom-->
<!--dependency-->
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<!--version in parent pom-->
</dependency>
</dependencies>
</project>
Project Aggregation 实战
需求:随着时间的推移,项目D的代码量越来越多,除了其基本功能外,还加入了很多其它的小功能。因此,其文件结构非常臃肿,给后续的开发和测试带来了巨大的挑战。
解决:首先,将项目D,拆分为多个子项目D1,D2,D3。(然后,把与项目B核心功能无关的子项目单独拿出来作为一个新的项目。)
拆分的过程简单列举如下,不详细展开:
- 根据业务逻辑,分析并决定要拆分成几个子模块
- 将各个子模块的共享逻辑比如 utils 类提取出来单独放到一个模块中
- 在做拆分前,先补全 integration test ,降低测试成本
- 在一段时间内集中精力把功能拆分完成,且通过测试
- 把与此同时在其它 branch 产生的 code change 合并到新模块中
母项目的 Parent Pom 如下,然后每个子项目各有自己的 Pom 文件。
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.mycompany.app</groupId>
<artifactId>my-module-d</artifactId>
<version>1.0</version>
<packaging>pom</packaging>
<modules>
<module>my-module-d1</module>
<module>my-module-d2</module>
<module>my-module-d3</module>
</modules>
</project>