maven - dependency management best practices

Generally, there are several sub-pom project modules under a parent pom project, and many jar packages that several sub-modules depend on, such as groupId/artifactid/version, are all the same, which has three disadvantages:

  1. Causes jar packages to depend on duplicates
  2. Causes duplicate dependencies of version numbers
  3. When upgrading a certain version number, several submodules need to be modified

 

1. Define all dependencies in the parent module

Configure dependencies in the parent module so that all submodules inherit automatically.

For example, define all the jars we need in the parent pom file:

 

<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>
 

 

In this way, submodules can directly use these jar packages as long as they inherit the parent module, which not only achieves the purpose of consistent dependencies, but also saves a large section of code.

 

However: this is a bit inappropriate. For example, a submodule, such as A, does not need the dependency of the parent module log4j, but it also inherits it directly, resulting in a bloated jar package and redundant dependencies.

 

2. Define all dependencyManagement in the parent module

We need a way to define all the jar package dependencies in the parent module, and which one needs to be specified in the submodule, which not only achieves centralized configuration, but also achieves the flexibility of what configuration the submodule needs.

而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,以更细化的方式管理依赖。这种做法与面向对象设计中使用组合而非继承也有点相似的味道。

事实上spring-boot非常的简洁已用,也是使用import的方式来管理那么多的jar包依赖的。

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326170981&siteId=291194637