想象一个正在编写的应用程序有2个依赖项;让我们称它们为依赖CCD_ 1和依赖B
。您无法控制这两个依赖项中的任何一个;它们不是您的库,但您的应用程序仍然依赖于它们。结果表明,依赖A
与依赖X
(1.0版)存在依赖关系;并且B对CCD_ 5(版本2.0)具有依赖性
根据Maven文档,依赖中介将用于决定使用哪个依赖:
依赖关系中介-它确定依赖关系的版本将在遇到工件的多个版本时使用。目前,Maven 2.0只支持使用"最接近的定义"这意味着它将使用与依赖项树中的项目。你总是可以保证版本,方法是在项目的POM中明确声明它。请注意,如果两个依赖版本在依赖树中处于相同深度,在Maven 2.0.8之前,还没有确定哪一个会赢,但由于Maven 2.0.9重要的是声明中的顺序:第一个声明获胜。
因此,假设我们首先声明依赖项A
,那么X
1.0版将在我们的应用程序中使用。这意味着依赖B
将在运行时使用X
版本1.0,其中as是针对A
0版本2.0编译的。如果B
使用一些仅2.0的功能,那么我们将得到一个运行时错误(NoSuchMethodError
、ClassNotFoundException
等),这是不好的。
因此,为了"修复"这一问题,我们可以从依赖A
中排除依赖X
,从而使用X
2.0版本。但是,哦,不!X
2.0版本不向后兼容,因此我们最终会从A
中得到运行时错误。
据我所知,Maven没有办法妥善解决这个问题。您所能做的就是希望获得其中一个库的源代码并自行修复。这是正确的吗?
为什么X
的两个版本都不可能打包到我的应用程序中,比如A
使用X
版本1.0,B
使用X
版本2.0,而我的应用中可用的X
版本是Maven通过依赖中介选择的。这是Java的限制,还是Maven的限制?这种情况常见吗?还有其他可能的解决方案吗?所有库都应该保证向后兼容性以避免这个问题吗?
不能将具有相同名称的两个类加载到一个类加载程序中。如果Maven允许您拥有同一工件的多个版本,这无疑会发生。因此,这是Maven能够解决的Java问题。
我不确定是否有一个包罗万象的解决方案。如果您控制了A
或B
,您可以使用着色将X
的使用重命名为不会发生冲突的内容,如maven着色插件的用途是什么,以及为什么要重新定位java包?中所述?。
一般来说,人们必须希望在库之间保持向后兼容性,并对生成的应用程序进行良好的测试,以确保没有问题。显然,您希望通过首先列出B
或在POM中显式列出X
来将Maven配置为包括x-2.0
而不是x-1.0
。
警告:大多数版本命名方案都允许在1.x.x和2.x.x之间进行中断更改,因此您可能会遇到问题。一些Maven项目(如ApacheCommonsLang)在更改主要版本时会使用新的工件ID和包结构,以避免这些冲突。