解决Maven依赖收敛问题

Dun*_*nes 37 java dependency-management maven maven-enforcer-plugin

我使用maven-enforcer-plugin来检查依赖性收敛问题.典型的输出是:

[WARNING] Rule 1: org.apache.maven.plugins.enforcer.DependencyConvergence failed 
  with message:
Failed while enforcing releasability the error(s) are [
Dependency convergence error for junit:junit:3.8.1 paths to dependency are:
+-foo:bar:1.0-SNAPSHOT
  +-ca.juliusdavies:not-yet-commons-ssl:0.3.9
    +-commons-httpclient:commons-httpclient:3.0
      +-junit:junit:3.8.1
and
+-foo:bar:1.0-SNAPSHOT
  +-junit:junit:4.11
]
Run Code Online (Sandbox Code Playgroud)

看到这条消息,我通常会通过排除传递依赖来"解决"它,例如

<dependency>
  <groupId>ca.juliusdavies</groupId>
  <artifactId>not-yet-commons-ssl</artifactId>
  <version>0.3.9</version>
  <exclusions>
    <!-- This artifact links to another artifact which stupidly includes 
      junit in compile scope -->
    <exclusion>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
    </exclusion>
  </exclusions>
</dependency>
Run Code Online (Sandbox Code Playgroud)

我想了解这是否真的是一个解决方案以及以这种方式排除库的风险.照我看来:

  • 如果我选择使用较新版本,"修复"通常是安全的.这依赖于库作者保持向后兼容性.

  • 通常对Maven构建没有影响(因为更接近的定义获胜),但是通过排除依赖性我告诉Maven我知道这个问题并因此安抚maven-enforcer-plugin.

我的想法是否正确,是否有另一种处理此问题的方法?我对那些关注一般情况的答案感兴趣 - 我意识到junit上面的例子有点奇怪.

小智 50

我们都同意JUnit永远不应该设置为另一个范围test.一般来说,我不认为存在另一种解决方案,而不是排除不必要的依赖关系,所以我们都同意你这样做是对的.

一个简单的案例:

正如Andreas Krueger所说,版本可能存在风险(我实际遇到过它).假设项目的依赖关系如下:

+-foo:bar:1.0-SNAPSHOT
  +-group1:projectA:2.0
     +-group2:projectB:3.8.1
  +-group2:projectB:4.11
Run Code Online (Sandbox Code Playgroud)

请注意,这仅仅是对案例的简化.看到这个依赖关系树,你将排除projectA给出的依赖项projectB:

<dependency>
  <groupId>group1</groupId>
  <artifactId>projectA</artifactId>
  <version>2.0</version>
  <exclusions>
    <exclusion>
      <groupId>group2</groupId>
      <artifactId>projectB</artifactId>
    </exclusion>
  </exclusions>
</dependency>
Run Code Online (Sandbox Code Playgroud)

在使用maven打包项目后,剩余的依赖项将是group2-someProjectB-4.11.jar,版本4.11而不是3.8.1.一切都会好的,项目会运行而不会遇到任何问题.

然后,过了一会儿,假设你决定升级到下一个版本的项目A 3.0版,它增加了新的强大功能:

<dependency>
  <groupId>group1</groupId>
  <artifactId>projectA</artifactId>
  <version>3.0</version>
  <exclusions>
    <exclusion>
      <groupId>group2</groupId>
      <artifactId>projectB</artifactId>
    </exclusion>
  </exclusions>
</dependency>
Run Code Online (Sandbox Code Playgroud)

问题是您还没有意识到 projectA 3.0版还将其依赖项projectB升级到5.0版:

+-foo:bar:1.0-SNAPSHOT
  +-group1:projectA:3.0
     +-group2:projectB:5.0
  +-group2:projectB:4.11
Run Code Online (Sandbox Code Playgroud)

在这种情况下,您之前所做的排除将排除projectB 5.0版.

但是,projectA 3.0版需要项目B 5.0版的改进.由于排除,在使用maven打包项目后,剩余的依赖项将是group2-someProjectB-4.11.jar,版本4.11而不是5.0.在您使用projectA的任何新功能时,该程序将无法正常运行.

什么是解决方案?

我在Java-EE项目中遇到了这个问题.

一个团队开发了数据库服务.他们把它打包成projectA.每次他们更新服务时,他们还会更新一个列出所有当前依赖项和当前版本的文件.

ProjectA是我正在开发的Java-EE项目的依赖项.每次服务团队更新ProjectA时,我都会检查版本的更新.

事实上,排除依赖是没有害处的.但每次更新已设置排除的依赖项时,您必须检查:

  • 如果这种排除仍然有意义.
  • 如果您需要在自己的项目中升级已排除的依赖项的版本.

我猜maven排除就像厨房刀.它很锋利,不费力地切蔬菜,但在处理时需要小心......