解决Maven中的依赖冲突

Maven依赖冲突确实很难解决。这篇文章的目的是让读者更好地理解什么是版本冲突以及为什么最好避免它们。我将从一个简短的故事开始,大多数读者可能会涉及到这个故事。
故事
首先,想象一下您已经开始着手开发一个有趣的大型项目,该项目使用许多不同的技术库,这些使您的工程师工作变得更加轻松。另外一个好处是,Maven可以管理库下载以及所选择的库版本。因此可以轻松更新它们。该项目的开发将继续进行,直到有一天您遇到了一个库,该库大大降低了身份验证开发的复杂性;然后,您决定将其包含在您的项目中。
但是突然之间,您的代码行2223中出现错误,该行与您正在处理的行不同。首先想到的是,“多么奇怪!那行代码之前从未失败过;这一定是我的代码中的错误;我一定是错误地创建/配置了一些东西”。但是,您意识到该代码没有任何问题。更彻底的调试过程“可能”表明,您不知道的库类中存在NullPointerException或NoSuchMethodException。立即的反应是将库依赖关系更新为较新的版本。但这不能解决问题。接下来要做的是查看库类本身的代码。发现该方法/类根本不存在;即使更新了添加到项目中的新库。
此外,当您决定访问本地Maven存储库.m2时,事情变得更加奇怪 ,并且发现同一库有两个不同的版本。您的项目使用的是旧版本,您不知道为什么…
恭喜你!您刚刚发现了导致项目崩溃的库的版本冲突。
注意:在故事中添加了身份验证库时,就可以做到这一点。
为什么会发生?
由于依赖关系可以链接到具有不同版本的其他依赖关系,因此会产生冲突。基于此,我们可以为项目X绘制一个依赖关系树方案 来解释这一点:

从上面的树形方案中可以明显看出, 即使我们没有在POM中明确指定它们,我们的项目 X也会使用所有库(Y,Z和G)。
实际上,在这种情况下, 即使您不知道该库存在,库 Z也会作为Maven依赖库导入到您的项目中。这种依赖关系称为 传递依赖关系。
由于 Y 和 G 依赖于Z的不同版本 ,因此我们创建了库冲突版本。该项目 在运行时只能使用一个版本的 Z库(1.0或2.0);但不是两者兼而有之。如果我们使用的库版本与另一个库不兼容;该项目最终可能会产生错误并崩溃。让我们假设库 Z 是我们项目中错误的根源。并且我们想知道哪个版本的 Z 会导致错误。
我们正在使用哪个Z版本?
我们的项目 X 使用称为依赖关系机制的Maven默认机制 来解决依赖关系,并知道要使用哪个库。
让我们看看依赖机制是如何工作的。
首先,将使用库的版本,其节点最接近依赖关系树中的根(项目 X)。但是,如果同一库有多个版本-节点在树中处于同一级别,会发生什么情况?在这种情况下,将使用找到的第一个库版本。这意味着库版本的选择取决于POM文件中的依赖关系顺序,其中首先声明的那些依赖关系将首先被选择。
如何解决冲突
解决上述冲突的方法有两种。第一个也是最简单的解决方案是 在 X的POM文件中将库G导入到 库Y之前 ;正如我上面解释的。但是,更巧妙的解决方案是将Z的最新版本(2.0)导入 为X的直接依赖项 。在 X的POM文件中。幸运的是,如果库Z 支持向后兼容(因为库 Y 使用 Z的v1.0),则后一种解决方案将起作用 。在这种情况下,需要进行测试以提高可靠性
重要说明:如果存在版本冲突,并不总是意味着您的项目将崩溃,当您使用很多库时通常会发生版本冲突,但是我们必须注意使用的库版本不会使我们的崩溃项目。
如何更快地发现冲突?
上面的故事中提到的问题是微不足道的,我们很幸运能够尽快解决。但是,有时候,找到依赖冲突不是一件容易的事。即使您已经知道该错误不是由您的代码逻辑引起的。
拥有一个测试项目中哪些库冲突的工具不是很好吗?你真幸运! Enforcer – Maven的爱铁拳– 就是这样做的。Enforcer可以通过分析POM文件中声明的所有库来帮助开发人员解决Maven中的依赖冲突。
该插件使用了许多不同的规则,但我们只对以下一个感兴趣:
dependencyConvergence –确保所有依赖项都收敛到同一版本。
让我们通过在pom.xml中编写插件来配置该插件以使用该规则:


org.apache.maven.plugins
maven-enforcer-plugin
1.4.1




通过以上配置,您可以 通过项目的命令行(mvnforcer:enforce)执行目标 forcer:enforce;或将目标绑定到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

如上所示,Enforcer编写了一个依赖关系树,其中的根是我们的项目“ conflict-info”。
在这种情况下,库log4j存在版本冲突。我们有两个log4j库版本(1.2.17和1.2.16)。
log4j的版本1.2.16取决于项目“ conflict-info”;而log4j的1.2.17版本则取决于“ slf4j-log4j12”。在编译和运行时,将使用log4j 1.2.16版,因为它的节点最接近我们项目依赖树中的根。由于在运行时只能使用一个库版本,因此“ slf4j-log4j12”将使用相同的版本。
请注意,并非所有的依赖版本冲突都会使您的项目崩溃。Maven的 依赖关系机制 负责选择库版本,如前几节所述。
最后,有更好的机会避免依赖版本冲突;提取依赖项(和首选版本)作为项目的直接子项。这样可以确保所选版本在该库的所有子依赖项中使用;前提是所选版本不会使项目崩溃。
结论
该结论提供了有关版本冲突以及如何在项目中解决它们的更多信息。
解决冲突的方法还有很多。甚至还有几百页的书,也说明了使用不同Maven配置的解决方案。本文仅描述解决这些问题的一种方法。
最后,开发这么多年我也总结了一套学习Java的资料与面试题,如果你在技术上面想提升自己的话,可以关注我,私信发送领取资料或者在评论区留下自己的联系方式,有时间记得帮我点下转发让跟多的人看到哦。在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/zhaozihao594/article/details/105475528