冲突依赖关系:如何选择?

3
让我们以项目A及其依赖项(包括传递依赖关系)为例。如果我查看依赖树,我会发现在一条路径的末尾,我有slf4j-api:1.6.4,在另一条路径的末尾,我有slf4j:1.6.1。
我该选择哪个依赖项呢?如果我选择slf4j:1.6.4,则我的classpath中没有版本1.6.1,那么我如何知道版本1.6.4是否与使用版本1.6.1的代码兼容?
我不理解,因为最终我的classpath上只有一个slf4j版本。
谢谢。
2个回答

2

Maven旨在管理这种传递依赖,并确保classpath上只存在一个jar版本。

如何查看Maven正在做什么

依赖插件将演示Maven代表您所做的工作(通过各种POM向下搜索并确定谁还声明了对同一模块的依赖)。

[INFO] [dependency:tree]
[INFO] org.apache.maven.plugins:maven-dependency-plugin:maven-plugin:2.0-alpha-5-SNAPSHOT
[INFO] +- org.apache.maven.reporting:maven-reporting-impl:jar:2.0.4:compile
[INFO] |  \- commons-validator:commons-validator:jar:1.2.0:compile
[INFO] |     \- commons-digester:commons-digester:jar:1.6:compile
[INFO] |        \- (commons-collections:commons-collections:jar:2.1:compile - omitted for conflict with 2.0)
[INFO] \- org.apache.maven.doxia:doxia-site-renderer:jar:1.0-alpha-8:compile
[INFO]    \- org.codehaus.plexus:plexus-velocity:jar:1.1.3:compile
[INFO]       \- commons-collections:commons-collections:jar:2.0:compile

通常会选择模块的最新版本,这是有道理的,因为某些模块可能使用仅在日志库的最新版本中才可用的方法。实际上,通常是弃用方法的删除导致编译问题,当依赖代码未与之保持同步时...

如何告诉Maven该做什么

如果您想对所选版本拥有更多控制权,则需要按以下方式指定依赖版本范围:

<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>[3.8,4.0)</version>
    <scope>test</scope>
</dependency> 

以下是功能描述:

希望这可以帮助到您。


1

这是一个与 C/C++ 中的 "DLL Hell" 相关的旧问题,被称为 "Jar Hell"。

在传递依赖项的情况下,您无法控制版本,并且无法保证不同版本兼容。在记录器的次要版本更改的简单情况下,它们很可能是兼容的。但是,在一般情况下,您将遇到冲突。

OSGi 部分是为了解决这个问题而开发的。我个人使用 Apache Felix OSGi 实现。

问题源于 Java 类加载器。它无法加载具有相同包和类名的两个类,这意味着它无法加载两个版本的 slf4j 以满足您的约束条件。

OSGi 是一个运行在 JVM 之上的运行时框架。与直接在 JVM 上使用默认类加载器运行 Jar 不同,您需要在 OSGi 实例中运行您的 Jar。 这需要在 Jar 的清单文件中添加一些元数据,这些 Jar 被称为 Bundle。 OSGi 为每个 Bundle 提供了自己的 ClassLoader,允许传递依赖项的分离。每个依赖项都将是独立的 Bundle,并能够在其 Bundle 的隔离 ClassLoader 中加载 slf4j 版本,而没有命名冲突。


1
我不同意。Maven通过确保类路径上只有一个jar存在来避免“jar hell”。Maven文档说明了如何通过声明版本范围来控制这些版本。但在实践中,我从未使用过此功能。 - Mark O'Connor
1
OSGi是一个很棒的技术,但它解决的是部署依赖管理的问题。而提出的问题涉及构建时依赖管理,具体使用Maven来解决。 - Mark O'Connor
1
@MarkO'Connor 确保类路径上只有一个jar文件在一定程度上对我有所帮助。如果代码的一部分使用版本1.0上特定的API(而不是2.0),而另一部分使用版本2.0上特定的API(而不是1.0),那么它怎么能正常工作呢? - manash
1
@MarkO'Connor “总之,这不是Maven的错,而是第三方模块管理的问题。”没错,这也正是OSGi所提供的。 - MattRS
1
最简单的测试是“是否编译通过”。这肯定会解决过时API可能存在的问题。运行时兼容性更具挑战性(在Java中,有些库仅在运行时链接)。解决方法是全面的单元测试和/或功能测试集合。 - Mark O'Connor
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接