使⽤maven⼯具解决jar包冲突或重复加载的问题
在使⽤maven开发项⽬的过程中,经常会遇到jar包重复加载或者jar包冲突的问题的,但是由于有些jar是由于maven的依赖加载⾃动加载进来的,
⽽不是开发者⾃⼰配置的,特别是当项⽬中pom中配置的jar包依赖本⾝很多时,开发者靠⾃⼰的经验,有时很难出是哪个jar的加载导致加载了
多余的依赖jar,从⽽产⽣冲突。
今天刚好遇到⼀个借⽤eclipse中的maven插件解决jar包依赖冲突的问题,分享⼀下。
项⽬中出现的问题如下:
Caused by: java.lang.NoClassDefFoundError: Could not initialize class org.apache.log4j.Log4jLoggerFactory
后经⽹上搜索加边上⼤⽜指点发现:
log4j-over-slf4j.jar 和 slf4j-log4j12.jar 在同⼀个classpath下就会出现这个错误。
解决⽅法:
将slf4j-log4j12.jar从相关的jar中排除
但是查看maven项⽬中的pom⽂件,⾃⼰并没有配置这个jar的依赖,猜测是maven加载其他jar引⼊的依赖包。
打开l⽂件,在Dependency Hierarchy(依赖列表)中查看jar包的依赖层次关系。
在过滤栏中输⼊log4j,右侧出现了log4j相关包的依赖结构,左侧则是l全部依赖包的列表展⽰。
直接在右侧选中zookeeper底下的slf4j的jar包,右键选择Exclude,然后保存l。这样在加载zookeeper的jar包时就不会再加载slf4j 的jar包。
修改后对应的dependency⽂件如下:
<dependency>
<groupId>keeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.4.6</version>
<exclusions>
<exclusion>
<artifactId>slf4j-log4j12</artifactId>
<groupId>org.slf4j</groupId>
</exclusion>
</exclusions>
</dependency>
这样就能通过filter过滤快速到对应jar,并知道他的依赖关系,快速解决项⽬中的jar包冲突问题。
补充知识:解决Maven重复依赖问题(同⼀个jar,多个版本)
问题描述
现在开发项⽬,⼀般都会创建maven⼯程,⽤它来管理依赖实在是⽅便了,当然它还有其它⽤途。但是在实际的情况中往往会有重复依赖的问题,⽐如创建的⼯程A,依赖了b-1.0.jar,⽽b-1.0.jar⼜依赖了d-1.0.jar(这个我们本⾝是不能直接看到的),同时我们⾃⼰的⼯程⼜依赖了d-2.1.jar,或者⼯程A依赖了c-1.0.jar,c-1.0.jar依赖了d-2.0.jar,显然,d.jar有3个版本,3者之间是重复的,甚⾄是冲突的。如下图所⽰:
重复依赖会怎么样?
⾸先从⼯程⾓度来讲,引⽤了同⼀个Jar的不同版本,这肯定是依赖有问题,或者就是错误的。
其次,重复依赖,在项⽬启动过程当中可能会有⼀些警告信息。
当然,最重要的是引发代码异常,最常见的就是NoSuchMethod。
解决思路
寻重复引⽤的jar。
定位这些Jar在哪⾥被引⽤了。
接下来需要分析舍与留,原则上保留⾼版本,⼤多数情况下是向下兼容的。但是不⼀定,有时候也得保留低版本,或者有时候两者都需要保留。
如果是⼀个⼯程,其实处理起来还⽐较好处理。但是如果有多个⼯程,最终我们可能将所有的依赖合在⼀块⼉。处理起来可能会稍微⿇烦些,⽐如⼯程1依赖了2.1版本,⼯程2依赖了2.2版本,你把⼯程1的2.1的依赖去掉,但同时还需要把2.2的加在⼯程1上⾯,否则可能编译不通过。
最重要的就是,调整之后,尽可能做全⾯测试。特别是⼀些间接依赖,如果去除的话,编译不会有问题,但运⾏起来会有问题。
具体解决过程
上述5个步骤,重点说⼀下1和2.
寻重复引⽤的jar
观察法:把所有的jar依赖打包到同⼀个⽬录下,观察。
运⾏法:运⾏阶段会报错,⼀旦报错,基本上就定位到了。
扫描法:专业的测试⼈员,可以进⾏扫描jar包并统计。
搜索法:依靠maven进⾏搜索,这个⽅法在接下来会讲到。
定位Jar被依赖的地⽅
在maven⼯程处打开命令⾏,输⼊:
mvn dependency:tree -Dverbose >
这个命令会把这个⼯程l⾥⾯所有的依赖通过树的形状展⽰出来,:
树形结构其实看得⽐较清楚,⾥⾯有⼀些关键信息,⽐如:
omitted for duplicate
这个意思是依赖是重复的,当然这个没有关系。
当然还有⼀些冲突提醒,上图没有,如下:
omitted for conflict with 0.5.3
maven打包本地jar包显⽰就是这个版本与0.5.3这个版本冲突了,这个也是我上⾯说到的搜索法,你可以直接搜索“conflict”这个单词,就可以了。当然这种⽅式仅限单个⼯程。
拿到这棵树以后,怎么办呢?
前提是我们已经知道了哪个jar包冲突了,那直接就在⽂本⾥⾯搜索,到不同版本的引⽤之处,然后慎重考虑之后,通过exclusions标签进⾏去除,如下:
<dependency>
<groupId>jaxen</groupId>
<artifactId>jaxen</artifactId>
<version>1.1.1</version>
<exclusions>
<exclusion>
<groupId>xerces</groupId>
<artifactId>xercesImpl</artifactId>
</exclusion>
</exclusions>
</dependency>
到此结束。去除的同时需要考虑的⼀些问题,在解决思路⾥⾯提及了⼀些。希望能给⼤家⼀个参考,也希望⼤家多多⽀持。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论