用好这几个技巧,解决Maven Jar包冲突易如反掌

栏目: IT技术 · 发布时间: 5年前

内容简介:大家在项目中肯定有碰到过本地运行报项目中明明定义着某个jar包版本为

前言

大家在项目中肯定有碰到过 Maven 的Jar包冲突问题,经常出现的场景为:

本地运行报 NoSuchMethodErrorClassNotFoundException 。明明在依赖里有这个Jar包啊。怎么运行不了!?

项目中明明定义着某个jar包版本为 2.0.2 ,怎么打包之后变成 2.5.0 了!?

A项目引xxx.jar包运行好好的,B项目同样引入xxx.jar后,运行报错了。。是B项目有问题,还是xxx.jar包有问题!?

本地环境和测试环境运行的好好的,到了生产就报一堆 NoSuchMethodError ,是我人品有问题还是生产环境有问题!?

这样的问题如果不熟悉 maven 依赖机制的同学排查起来,估计挺头痛的。

而且 maven 依赖结构不好的项目,在引入新的Jar包时的风险也是巨大的。小则影响性能,大则引起生产发布和运行时异常。

其实以上问题的根源都来自于 Maven 的Jar包冲突和使用不当的依赖传递。这篇文章我就好好分析下以下3个内容:

POM

依赖传递原则

几乎所有的Jar包冲突都和依赖传递原则有关,所以我们先说 Maven 中的依赖传递原则:

最短路径优先原则

假如引入了2个Jar包A和B,都传递依赖了Z这个Jar包:

B -> X -> Z(2.0)

那其实最终生效的是Z(2.0)这个版本。因为他的路径更加短。如果我本地引用了Z(3.0)的包,那生效的就是3.0的版本。一样的道理。

最先声明优先原则

如果路径长短一样,优先选最先声明的那个。

B -> Z(2.5)

这里A最先声明,所以传递过来的Z选择用3.0版本的。

Jar包冲突的原理

假设我们项目中依赖了A和B两个Jar包。而A和B各自又有以下传递依赖

B -> X -> Y -> Z(2.5)

那最终系统中Z包就产生了冲突,2.0和2.5两个版本冲突。但是classpath中只会依赖一个版本的Z包。根据传递依赖的 最短路径优先原则 ,最终依赖的应该是2.0版本。

如果Y包中用了Z包2.5版本中新的method时候,当运行到这段逻辑的时候。就会报 NoSuchMethodError 了。因为本来依赖的是2.5版本,但是因为Jar包冲突 Maven 选择了2.0版本,2.0版本中又没有这个新的method,导致出错。

但要注意的是,不是所有冲突都会引起运行异常。相反,大部分公司的项目都会有一些Jar包冲突,但其实没有造成运行时的问题。

这是因为很多传递依赖的Jar包,不管是2.0版本也好,2.5版本也好,都可以运行。

只有高版本Jar包不向下兼容,或者新增了某些低版本没有的API才有可能导致这样的问题

定位冲突

IDEA提供了一个 maven 依赖分析神器: Maven Helper

用好这几个技巧,解决Maven Jar包冲突易如反掌

用这个插件能很好的显示出项目中所有的依赖树和冲突

用好这几个技巧,解决Maven Jar包冲突易如反掌

这里面红色高亮的部分,就表明这个Jar包有了冲突。选中这个jar包,可以看到这2个版本的冲突的来源。

上图的例子,表明 cruator-client 这个Jar包,有2个传递依赖,分别为2.5.0版本和4.0.1版本。冲突的描述为:

omitted for conflict with 2.5.0. 由于与2.5.0版本冲突而被省略

具体的层级在右边也一目了然了,所以 maven 最终根据 最短路径优先原则 选择了2.5.0版本,4.0.1版本被忽略。

这时候有同学会问: 本地环境我可以利用 Maven Helper 来定位,那么预生产或者生产环境呢。又没有IDEA,如何定位冲突的细节?

可以利用mvn命令来解决:

mvn dependency:tree -Dverbose

此处一定不要省略 -Dverbose 参数,要不然是不会显示被忽略的包的

用好这几个技巧,解决Maven Jar包冲突易如反掌

其实mvn命令行一样好用。非常清晰明确。

解决Jar包冲突的几个实用技巧

排除法

还是上面的那个例子,现在生效的是2.5.0,如果想生效4.0.1。只需要在2.5.0上面点 exclude 就行了。

用好这几个技巧,解决Maven Jar包冲突易如反掌

版本锁定法

如果很多个依赖都传递了Jar包A,涉及了很多个版本,但是你只想指定一个版本。用排除法一个个去 exclude 太麻烦,而且 exclude 在pom文件中也会体现,太多的话,也影响代码整洁和阅读感受。

这时候需要用到版本锁定法

何谓版本锁定法?公司的项目一般都会有父级pom,你想指定哪个版本只需要在你项目的父POM中(当然在本工程内也可以)定义如下:(还是举上个例子,指定4.0.1版本)

<dependencyManagement>
    <dependency>
        <groupId>org.apache.curator</groupId>
        <artifactId>curator-client</artifactId>
        <version>4.0.1</version>
    </dependency>
</dependencyManagement>

锁定版本法可以打破2个依赖传递的原则,优先级为最高

锁定版本后,依赖树为:

用好这几个技巧,解决Maven Jar包冲突易如反掌

都统一变成4.0.1,锁定版本有一个好处:版本锁定并不排除Jar包,而且显示的把所有版本不一致的Jar包变成统一一个版本,这样在阅读代码时比较友好。也不用忍受一大堆的 exclude 标签。

如何写一个干净依赖关系的 POM 文件

我本人是有些轻度代码洁癖的人,所以即便是pom文件的依赖关系也想干净而整洁。如何写好干净的POM呢,作者认为有几点技巧要注意:

<dependencyManagement>
mvn dependency:analyze-only
mvn dependency:analyze-duplicate

最后

其实庞大的项目依赖传递也一定多。但是不管多复杂的依赖关系,看到不要害怕。就这么几条原则,细心的去分析,所有的依赖都有迹可循。

这些传递依赖如果管理的好,能让你的维护成本大大降低。如果管不好,这群野孩子每一个都可能是引发下一个 NoSuchMethodError 的导火索。

关注作者

如果你喜欢作者的文章,欢迎微信公众号关注 「 元人部落

一个只做原创的技术科技分享号

关注后回复“ 资料 ”获取50G的技术资料


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

The Cult of the Amateur

The Cult of the Amateur

Andrew Keen / Crown Business / 2007-6-5 / USD 22.95

Amateur hour has arrived, and the audience is running the show In a hard-hitting and provocative polemic, Silicon Valley insider and pundit Andrew Keen exposes the grave consequences of today’s......一起来看看 《The Cult of the Amateur》 这本书的介绍吧!

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

MD5 加密
MD5 加密

MD5 加密工具

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具