Maven的依赖可以真的很难解决冲突。 这篇文章的目的是让读者更好地理解什么是版本冲突,为什么最好避免它们。 我将开始一个短篇故事,大多数读者可能涉及到。
这个故事
首先,想象你已经开始致力于一个大型和有趣的项目,它使用许多不同的技术库,使你的生活更容易为工程师。 作为一个额外的好处,Maven管理图书馆下载的库版本的选择; 所以他们可以很容易地更新。 开发的项目继续下去,直到有一天你遇到一个库,减少了验证的复杂性显著发展; 然后决定包括在您的项目。
但突然间,你得到一个错误的2223行代码,这是一条不同的你。 那些浮现在你脑海的第一件事是,“多么奇怪! 这行代码没有失败; 它必须是一个错误在我的代码; 我必须创建/配置不正确”。 然而,你意识到的代码没有任何问题。 更彻底的调试过程“可能”显示,有一个NullPointerException或NoSuchMethodException库类,您不知道存在。 第一反应是更新新版本的库依赖关系; 但这并不能解决问题。 接下来你要做的就是看看图书馆类本身的代码; 发现该方法/类不存在; 即使更新新库添加到您的项目。
此外,事情变得更加不可思议当你决定访问本地Maven存储库.m2,你发现有两个不同版本的库。 您的项目使用的是旧版本,不知道为什么…
恭喜你! 你刚刚和版本库冲突发现撞您的项目。
请注意:你把它当你添加身份验证库的故事。
它为什么会发生?
由于依赖关系可以与其他依赖不同的版本,可以产生冲突。 在此基础上,我们可以画一个依赖树为我们的项目计划X解释:
从上面的树方案中,很明显,我们的项目X将使用的所有库(Y,Z,H)即使在POM我们没有显式地指定它们。
实际上,在这种情况下,图书馆Z将导入到你的项目作为一个Maven依赖库,即使你不知道图书馆的存在。 这种依赖是更好的被称为过渡依赖。
自Y和G取决于不同版本的Z,我们已经创建了一个库版本冲突。 这个项目可以使用只有一个版本的Z在运行时库(1.0或2.0); 但不能两者兼得。 如果我们使用一个不兼容的版本库与另一个库; 项目最终可能会产生错误和崩溃。 让我们假设库Z在我们的项目错误背后的罪魁祸首; 我们想知道哪个版本的Z正在创建的错误。
我们使用Z版本?
我们的项目X使用Maven称为默认机制依赖机制解决,知道使用哪个库的依赖关系。
让我们看看依赖机制是如何工作的。
首先,图书馆的版本的节点是根(最近的项目X)将使用依赖关系树。 然而,如果有几个版本的相同的库的节点都在相同的水平在树上? 在这种情况下,发现第一个库版本使用。 这意味着库版本的选择取决于依赖POM文件里面了,那些依赖宣布第一将选择。
如何解决冲突
有两种方法可以解决上述冲突。 第一和最简单的解决方案是导入库G在图书馆Y内部X的POM文件; 正如我上面解释道。 然而,一个简洁的解决方案是进口的最后版本Z(2.0)的直接依赖关系X; 内部XPOM文件。 有一些运气,后者的解决方案如果图书馆工作Z支持向后兼容(如图书馆Y使用Z的v1.0)。 在这种情况下测试需要增加可靠性
重要提示:如果有版本冲突,它并不总是意味着你的项目将会崩溃,通常会有版本冲突,当你使用大量的库,但我们必须注意,不会崩溃,我们的项目使用的库版本。
我怎么能更快地发现冲突?
提出的问题在上面的故事非常简单,我们很幸运,快速解决它。 然而,有时候,它不是一项容易的任务找到依赖冲突; 即使你已经知道,这个错误不是来自你的代码逻辑。
不是很好有一个工具,测试库项目中冲突吗? 你很幸运!
执行者- Maven的爱的铁拳
就是干这个的。 执行者可以帮助开发者解决依赖冲突Maven POM文件中声明通过分析所有库。
这个插件使用很多不同的规则,但是我们只是感兴趣:
dependencyConvergence
-确保所有依赖项收敛于相同的版本。
让我们配置插件来使用规则写在pom.xml:
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-enforcer-plugin</artifactId>
<version>1.4.1</version>
<configuration>
<rules><dependencyConvergence/></rules>
</configuration>
</plugin>
</plugins>
从上面的配置,您可以执行的目标执行者:执行通过项目的命令行(mvn执行者:执行); 或者通过绑定一个Maven目标阶段。 这是非常有用的找到任何依赖冲突,项目可能会崩溃。 一旦执行,插件返回树列表显示所有冲突(如果有的话)在项目:
Dependency convergence error for log4j:log4j:1.2.17 paths to dependency are:
+-com.ricston.conflict:conflict-info:2.1.3-SNAPSHOT
+-org.slf4j:slf4j-log4j12:1.7.6
+-log4j:log4j:1.2.17
and
+-com.ricston.conflict:conflict-info:2.1.3-SNAPSHOT
+-log4j:log4j:1.2.16
执行者依赖树写道,正如上面你可以看到的,根源在哪里我们的项目“conflict-info”。
在这种情况下,图书馆log4j版本冲突。 我们有两个图书馆log4j版本(1.2.17和1.2.16)。
log4j版本1.2.16是依靠由项目“conflict-info”; 虽然版本1.2.17取决于log4j的“slf4j-log4j12”。 在编译和运行时,将使用log4j版本1.2.16,因为它的根节点最近的我们的项目依赖关系树。 因为只有一个库版本可以在运行时使用,同一版本将用于“slf4j-log4j12”。
请注意,并不是所有项目依赖版本冲突会崩溃。 Maven的依赖机制负责选择库版本,在前面的部分。
最后,为了有更好的机会避免依赖版本冲突; 提取的依赖(和首选的版本)作为项目的直接的孩子。 这将确保所选的版本是用于所有子库的依赖关系; 提供选择的版本不崩溃。
结论
这一结论提供进一步信息版本冲突,如何克服他们在您的项目中。
还有许多其他的方法来解决这种冲突; 甚至还有图书数百页使用不同的Maven配置说明解决方案。 本文描述了只有一个解决这些问题的方法。