maven中类冲突,包依赖NoClassDefFoundError以及方法NoSuchMethodError的问题定位以及解决

时间:2024-03-24 08:01:58

作为java程序员,我们在项目开发的过程中,肯定需要依赖大量的第三方依赖包,通常我们都是使用maven构建工具来管理第三方工具包的,既然有依赖第三方包,那么肯定也会遇到jar包冲突的问题,那这个时候,我们就需要定位问题所在,定位问题所在首先需要理解冲突的原理。

1. 下面首先讲解maven中如何引入jar包,通过maven的坐标引入jar包

    maven中类冲突,包依赖NoClassDefFoundError以及方法NoSuchMethodError的问题定位以及解决

2. maven jar包的依赖的原理

   maven中jar包的依赖是传递依赖,以上图为例,maven在解析zookeeper的包时,不但会解析zookeeper包,可能还会解析zookeeper内部依赖的包,可能还会解析zookeeper内部依赖的包所依赖的包,依赖关系不断传递下去,直至没有依赖关系,我们在maven中打开zookeeper的pom,我们可以看到zookeeper还依赖了slf4j-api的jar包,commons-collections包

maven中类冲突,包依赖NoClassDefFoundError以及方法NoSuchMethodError的问题定位以及解决

maven中类冲突,包依赖NoClassDefFoundError以及方法NoSuchMethodError的问题定位以及解决

3. maven中jar包冲突产生的原因

   maven 处理依赖冲突的方式:

   若项目中多个Jar同时引用了相同的Jar时,会产生依赖冲突,但Maven采用了两种避免冲突的策略,因此在Maven中是不存在依赖冲突的。

3.1 短路优先
本项目——>A.jar——>B.jar——>X.jar
本项目——>C.jar——>X.jar
若本项目引用了A.jar,A.jar又引用了B.jar,B.jar又引用了X.jar,并且C.jar也引用了X.jar。 
在此时,Maven只会引用引用路径最短的Jar。

3.2 声明优先
若引用路径长度相同时,在pom.xml中谁先被声明,就使用谁。

3.3 假设 有以下两个依赖关系:其中C1和C2是两个相同的jar包,他们只是version版本号不同

                A->B->C1 依赖关系: A包依赖B包,B包依赖C1包

                E->D->C2 依赖关系: E包依赖D包,D包依赖C2包

当我们在项目中同时引入了A包和E包,按照maven的依赖传递原理,那么我们相当于在项目中同时引入了两个C包,只是他们的version版本号不同,这时候就会出现冲突了,如果我们调用了C2中一个method方法,这个方法在C1中不存在(可能是C2高版本升级之后新添加的方法),那么jvm在进行类加载的时候,加载按照A->B->C1顺序,这个时候就会报NoSuchMethodError的错误,jar包冲突问题就出现了

下面举个例子:借助于maven-helper 这个插件

 maven中类冲突,包依赖NoClassDefFoundError以及方法NoSuchMethodError的问题定位以及解决

    上图中红色标注的就是冲突的地方:commons-collections 3.2.1 这个版本的依赖包产生冲突,冲突的地方在velocity-tools中,为了验证冲突的位置是否是在velocity-tools这里,我们打开All Dependencies as tree这里

maven中类冲突,包依赖NoClassDefFoundError以及方法NoSuchMethodError的问题定位以及解决

 查看上面的图,我们可以看到,有两个版本的commons-collections 依赖包,另外一个版本号是3.2,所以就产生jar包冲突了。

 4. maven中jar包产生冲突之后的解决方案

     既然有多个版本号的jar依赖存在,那我们就自然而然的想到,移除多余的jar包,只保留一个不就可以了,事实确实如此,我们可以通过移除内部依赖的jar包达到解决jar包冲突的目的。

4.1 移除的方式有两种,第一种是借助于maven helper插件中的Dependency Analyzer分析冲突的jar包,然后在提示冲突的jar包上面右击Exclude,然后刷新就可以了

 maven中类冲突,包依赖NoClassDefFoundError以及方法NoSuchMethodError的问题定位以及解决

maven中类冲突,包依赖NoClassDefFoundError以及方法NoSuchMethodError的问题定位以及解决

从上图中可以看出,commons-collections 这个冲突的jar已经不存在了

4.2  手动移除,这个是通过在pom中添加<exclusion>标签达到解决jar包冲突的目的

       maven中类冲突,包依赖NoClassDefFoundError以及方法NoSuchMethodError的问题定位以及解决

5. 为了减少jar包版本冲突问题,一般我们需要将这个被多模块引用的jar包统一管理起来,使用<dependencyManagement>在父的pom中声明,然后多个子的模块中引用,这个时候多个子的module中是不需要声明版本号的。

举个例子:

   maven中类冲突,包依赖NoClassDefFoundError以及方法NoSuchMethodError的问题定位以及解决

这是个多module项目,我们在父的pom中声明了一个ghub-commons  jar包,然后我们在子的module中直接引用即可。

上面所讲的可能只是解决包冲突的部分方案,具体的问题可能需要具体的去看待,问题不一样,解决方案就不一样。