解决Maven依赖收敛问题

问题描述 投票:0回答:3

我使用 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
例子有点奇怪。

java maven dependency-management maven-enforcer-plugin
3个回答
74
投票

我们都同意 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 版需要从 project B 5.0 版 进行改进。因为排除,用maven打包项目后,剩下的依赖是group2-someProjectB-4.11.jar,版本4.11,不是5.0。在您使用 projectA 的任何新功能的那一刻,该程序将无法正常运行。

解决方案是什么?

我在一个Java-EE项目中遇到过这个问题

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

ProjectA 是我正在处理的 Java-EE 项目的依赖项。每次服务团队更新 ProjectA 时,我也会检查版本更新。

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

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

我猜 Maven 排除就像菜刀一样。它很锋利,切菜毫不费力,但处理时需要小心......


3
投票

如果作为工件的 JUnit 在编译范围内作为依赖项出现,那么它是您的一个库的错误,在这里:ca.juliusdavies。

JUnit 应始终包含在测试范围内。因此,在成功构建时,它not 打包到生成的 .jar、.war 或 .ear 文件中。

一般来说,排除已经包含的依赖项没有坏处,因为库 1 和库 2 共享一个共同的依赖项。

当然,唯一可能发生的问题是库 1 和库 2 包含同一依赖工件的不同版本。 这可能会导致运行时错误,当库的功能发生变化时。 幸运的是,这种情况并不常见,除非版本号差异很大。通常,建议包含最新的依赖版本并排除旧版本。这在大多数情况下是可行的。

如果没有,检查你的项目一级依赖是否有更新


0
投票

在项目中使用 enforcer 时解决此依赖性问题的最佳方法, 应该在依赖管理中添加导致依赖的错误,即 pom.xml 就像这个 junit 导致了问题,所以选择更高的版本并添加为 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>

排除可以是其他解决方案,但我发现这样做更简洁。

© www.soinside.com 2019 - 2024. All rights reserved.