想象一下,正在编写一个具有2个依赖关系的应用程序;让我们称之为依赖A
和依赖B
。你无法控制这些依赖关系;它们不是你的库,但你的应用程序依赖于它们。事实证明,依赖A
依赖于依赖X
(版本1.0);和B依赖于X
(版本2.0)。
根据Maven documentation,依赖关系中介将用于决定使用哪种依赖关系:
依赖关系中介 - 这决定了依赖关系的版本 将在遇到多个版本的工件时使用。 目前,Maven 2.0仅支持使用“最近定义” 这意味着它将使用最接近的依赖版本 您的项目在依赖树中。你可以随时保证 版本通过在项目的POM中明确声明它。请注意,如果 两个依赖版本在依赖关系树中处于相同的深度, 直到Maven 2.0.8没有定义哪一个会赢,但从那以后 Maven 2.0.9这是声明中的顺序:第一个 宣言获胜。
因此,假设我们首先声明依赖A
,那么X
版本1.0将在我们的应用程序中使用。这意味着依赖项B
将在运行时使用X
版本1.0,其中针对X
版本2.0进行编译。如果B
使用的是某些仅限2.0的功能,那么我们会收到运行时错误(NoSuchMethodError
,ClassNotFoundException
等),这样做并不好。
因此,要“修复”此问题,我们可以从依赖项X
中排除依赖项A
,以便使用X
版本2.0。但是哦,不! X
版本2.0不向后兼容,因此我们最终会从A
获取运行时错误。
据我所知,没有办法用Maven正确解决这个问题。您所能做的就是希望获得其中一个库的源代码并将其自行修复。这是对的吗?
为什么X
的两个版本都无法打包到我的应用程序中,因此A
使用X
版本1.0,B
使用{{1}版本2.0,我的应用程序中可用的X
版本是Maven通过依赖中介选择的任何内容。它是Java的限制,还是Maven的限制?这种情况常见吗?还有其他可能的解决方案吗?是否所有库都应保证向后兼容以避免此问题?
答案 0 :(得分:2)
两个具有相同名称的类无法加载到一个类加载器中。如果Maven允许您拥有相同工件的多个版本,那么毫无疑问会发生这种情况。所以这是Maven所容纳的Java问题。
我不确定这是否有解决方案。如果您控制了A
或B
,则可以使用着色将X
的使用重命名为不会发生冲突的内容,如{{3 }}。
一般来说,人们必须希望在库之间保持向后兼容性并且很好地测试生成的应用程序以确保没有问题。显然,您希望将Maven配置为包含x-2.0
而不是x-1.0
,方法是首先列出B
或在POM中明确列出X
。
警告:大多数版本命名方案允许在1.x.x和2.x.x之间进行重大更改,因此您可能会遇到问题。一些Maven项目(例如Apache Commons Lang)在更改主要版本时将使用新的工件ID和包结构,以避免这些冲突。