一般一个父pom项目下面常常有好几个子pom项目模块,而且几个子模块依赖的很多jar包,比如groupId/artifactid/version都是相同的,这样有三个弊端:
- 造成jar包重复依赖
- 造成版本号重复依赖
- 升级某个版本号时,要修改好几个子模块
一、在父模块中定义全部dependencies
在父模块中配置dependencies,那样所有子模块都自动继承。
例如在父pom文件中定义好我们需要的全部jar:
<dependencies> <dependency> <groupId>junit</groupId> <artifactid>junit</artifactId> <version>4.8.2</version> <scope>test</scope> </dependency> <dependency> <groupId>log4j</groupId> <artifactid>log4j</artifactId> <version>1.2.16</version> </dependency> </dependencies>
这样子模块只要继承父模块就能直接使用这些jar包,不仅达到了依赖一致的目的,还省掉了大段代码。
然而:这么做是有些不妥的地方,例如某个子模块,比如A不需要父模块log4j的依赖,但也直接继承了,造成了jar包臃肿,多余依赖。
二、在父模块中定义全部dependencyManagement
我们需要一种在父模块中定义好全部的jar包依赖,而子模块需要哪一种指定哪一种,这样既做到了集中式配置,又做到了子模块需要什么配置什么的灵活性。
而dependencyManagement就可以做到。针对这个问题我们可以使用继承机制以及dependencyManagement元素就能解决这个问题。
dependencyManagement只会影响现有依赖的配置,但不会引入依赖。
例如我们可以在父模块中配置如下:
<dependencyManagement> <dependencies> <dependency> <groupId>junit</groupId> <artifactid>junit</artifactId> <version>4.8.2</version> <scope>test</scope> </dependency> <dependency> <groupId>log4j</groupId> <artifactid>log4j</artifactId> <version>1.2.16</version> </dependency> </dependencies> </dependencyManagement>
这段配置不会给任何子模块引入依赖,但如果某个子模块需要使用JUnit和Log4j的时候,我们就可以简化依赖配置成这样:
<dependency> <groupId>junit</groupId> <artifactid>junit</artifactId> </dependency> <dependency> <groupId>log4j</groupId> <artifactid>log4j</artifactId> </dependency>
不要的模块,就不需要引入,而dependencyManagement完美的做到了这点。
现在只需要groupId和artifactId,其它元素如version和scope都能通过继承父POM的dependencyManagement得到,如果有依赖配置了exclusions,那节省的代码就更加可观。
但重点不在这,重点在于现在能够保证所有模块使用的JUnit和Log4j依赖配置是一致的。而且子模块仍然可以按需引入依赖, 如果我不配置log4j
dependency,父模块中dependencyManagement下的log4j依赖不会对子模块产生任何影响。
然而,如果在父模块中引入了大量的jar包依赖,这个父模块的dependencyManagement就会包含大量的依赖,如果你想把这些依赖分类以更清晰的管理,那就不可能了。
三、使用import单独出dependencyManagement
此时为了应对父模块中引入了大量的jar包依赖造成父模块臃肿,我们需要一种可以把dependencyManagement放到外面去分开管理,这样很清晰很多,才能更好的管理更多的jar。
而import scope依赖能解决这个问题。
我们可以把dependencyManagement放到单独的专门用来管理依赖的POM中,然后在需要使用依赖的模块中通过import scope依赖,就可以引入dependencyManagement。
1、我们可以写这样一个用于依赖管理的子模块POM:
<project> <modelVersion>4.0.0</modelVersion> <groupId>wang.conge.demo</groupId> <artifactId>sample-dependency-infrastructure</artifactId> <packaging>pom</packaging> <version>1.0-SNAPSHOT</version> <dependencyManagement> <dependencies> <dependency> <groupId>junit</groupId> <artifactid>junit</artifactId> <version>4.8.2</version> <scope>test</scope> </dependency> <dependency> <groupId>log4j</groupId> <artifactid>log4j</artifactId> <version>1.2.16</version> </dependency> </dependencies> </dependencyManagement> </project>
2、然后我们的父模块只需要通过非继承的方式来引入这段依赖管理配置:
<dependencyManagement> <dependencies> <dependency> <groupId>wang.conge.demo</groupId> <artifactid>sample-dependency-infrastructure</artifactId> <version>1.0-SNAPSHOT</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>
3、最后我们的子模块需要哪个jar包就引入哪个jar包
<dependency> <groupId>junit</groupId> <artifactid>junit</artifactId> </dependency> <dependency> <groupId>log4j</groupId> <artifactid>log4j</artifactId> </dependency>
完美,有没有?
这样,父模块的POM就会非常简洁,由专门的子模块为pom的POM来管理依赖,也契合的面向对象设计中的单一职责原则。
此外,我们还能够创建多个这样的依赖管理POM,以更细化的方式管理依赖。这种做法与面向对象设计中使用组合而非继承也有点相似的味道。