解决Maven依赖项收敛问题

t1rydlwq  于 2023-03-07  发布在  Maven
关注(0)|答案(3)|浏览(228)

我使用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
]

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

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

我想知道这是否是一个真正的修复方法,以及以这种方式排除库所涉及的风险。

  • “修复”通常是安全的,只要我选择使用较新的版本。这依赖于库的作者保持向后兼容性。
  • 通常对Maven构建没有影响(因为更接近的定义获胜),但是通过排除依赖项,我告诉Maven我知道这个问题,从而安抚maven-enforcer-plugin。

我的想法是正确的吗?有没有其他的方法来处理这个问题?我对关注一般情况的答案很感兴趣-我意识到上面的junit例子有点奇怪。

kse8i1jr

kse8i1jr1#

我们都同意JUnit不应该被设置为test以外的其他作用域。一般来说,我不认为除了排除不需要的依赖性之外还有其他解决方案,所以我们都同意您这样做是正确的。

一个简单的案例:

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

+-foo:bar:1.0-SNAPSHOT
  +-group1:projectA:2.0
     +-group2:projectB:3.8.1
  +-group2:projectB:4.11

请注意,这仅仅是对您的情况的简化,看到这个依赖树,您将排除由projectA给出的依赖projectB:

<dependency>
  <groupId>group1</groupId>
  <artifactId>projectA</artifactId>
  <version>2.0</version>
  <exclusions>
    <exclusion>
      <groupId>group2</groupId>
      <artifactId>projectB</artifactId>
    </exclusion>
  </exclusions>
</dependency>

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

问题是您还不知道projectA版本3.0也已将其依赖项projectB升级到版本5.0:

+-foo:bar:1.0-SNAPSHOT
  +-group1:projectA:3.0
     +-group2:projectB:5.0
  +-group2:projectB:4.11

在这种情况下,您刚才所做的排除将排除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时,我也会检查版本的更新。

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

  • 如果这种排除还有意义的话。
  • 如果需要升级您自己项目中排除的依赖项的版本,请使用。

我猜专业排除就像菜刀一样,锋利,切菜毫不费力,但操作时需要小心......

avwztpqn

avwztpqn2#

如果JUnit作为一个工件在编译范围内作为一个依赖项出现,这是您的某个库的bug,如下所示:ca.juliusdavies.
JUnit应该始终包含在测试范围中,因此,在成功构建时,它不会打包到生成的.jar、.war或.ear文件中。
一般来说,排除已经包含的依赖项没有坏处,就像库1和库2共享一个公共依赖项一样。
当然,唯一可能发生的问题是库1和库2包含同一依赖工件的不同版本。这可能导致运行时错误,当库的特性发生变化时。幸运的是,这种情况并不常见,除非版本号的差异很大。一般来说,最好包含最新的依赖版本,排除旧版本。2这在大多数情况下是可行的。
如果没有,请检查项目的第一级依赖项是否有更新。

s8vozzvw

s8vozzvw3#

在项目中使用Enforcer时解决此依赖关系问题的最佳方法,应在依赖关系管理中添加导致依赖关系的错误,即像此junit中的pom.xml导致问题,因此选择更高版本并在pom.xml中添加为依赖关系

<dependency><groupId>junit_or_group_id_error_causing_dependency</groupId><artifactId>Junit_or_artifact_id_group_id_error_causing_dependency</artifactId><version>4.11_or_higher_version_of_error_causing_dependency</version></dependency>

排除可以是其他解决方案,但我发现它更清洁的方式做同样的事情。

相关问题