我使用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。 / p>
我的想法是否正确,是否有另一种处理此问题的方法?我对那些关注一般情况的答案感兴趣 - 我意识到上面的junit
例子有点奇怪。
答案 0 :(得分:48)
我们都同意JUnit永远不应该被设置为test
以外的另一个范围。一般来说,我不认为存在另一种解决方案,而不是排除不必要的依赖关系,所以我们都同意你这样做是正确的。
一个简单的案例:
正如Andreas Krueger所说,版本可能存在风险(我实际遇到过它)。假设项目的依赖关系如下:
+-foo:bar:1.0-SNAPSHOT
+-group1:projectA:2.0
+-group2:projectB:3.8.1
+-group2:projectB:4.11
请注意,这仅仅是对案例的简化。看到这个依赖树,你将排除projectA给出的依赖项目B:
<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>
问题是你还没有意识到项目版本3.0也已将其依赖项目B升级到版本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时,我都会检查版本的更新。
实际上,排除依赖项没有任何害处。但每次更新已设置排除项的依赖项时,您必须检查:
我猜maven排除就像厨房刀。它很锋利,不费力地切蔬菜,但在处理时需要小心......
答案 1 :(得分:3)
如果JUnit作为工件在编译范围内作为依赖项出现,则它是您的某个库的错误,例如:ca.juliusdavies。
JUnit应始终包含在测试范围内。因此,在成功构建时,不打包到生成的.jar,.war或.ear文件中。
一般来说,排除已包含的依赖项没有任何害处,因为库1和库2共享一个共同的依赖项。
当然,唯一可能出现的问题是库1和库2包含相同依赖工件的不同版本。当库的功能发生变化时,这可能会导致运行时错误。 幸运的是,除非版本号的差异很大,否则通常情况并非如此。通常,建议包含最新的依赖版本并排除旧版本。这大部分时间都是可行的。
如果没有,请检查项目的第一级依赖项是否有更新。