包冲突这个问题我们在开发程序时经常遇见,下面我们来分析下包冲突引起的原因及解决思路

错误现象

控制台提示:

Caused by:java.lang.NoSuchMethodError
Caused by: java.lang.ClassNotFoundException

这种报错很大可能是maven 项目里面jar包冲突引起的。

jar包冲突如何产生

在maven项目中当引入依赖时会将依赖的依赖一并引入到工程,例如当在项目中引入A的jar包时A的jar包又依赖了B的jar包,maven会将它们一并引入到工程。

<dependency>
            <groupId>io.netty</groupId>
            <artifactId>netty-buffer</artifactId>
            <version>4.1.9.Final</version>
        </dependency>

用maven helper这个插件可以观察到 netty-buffer这个jar又依赖了netty-common这个jar包。netty-buffer对应上面说的A,netty-common对应上面说的B。

android guava jar包冲突 jar包冲突原因_jar包


此时netty-buffer的版本为4.1.9.Final,如果开发者在pom文件又引入了netty-common的其它版本 如下图所示:

android guava jar包冲突 jar包冲突原因_jar_02


此时就netty-common这个jar包就冲突了。使用maven helper插件可以观察到:

android guava jar包冲突 jar包冲突原因_java_03


*假设程序使用了4.0.56Final这个版本的netty-commonjar包

如果此时4.0.56Final这个版本的包下面没有程序需要的某个类而在4.1.9Final这个版本的包下面才有这个类,程序运行时就会提示:

Caused by: java.lang.ClassNotFoundException

如果程序需要的某个类的一个方法在4.0.56Final这个版本里面没有,在4.1.9Final这个版本才有,此时程序运行时就会提示:

Caused by:java.lang.NoSuchMethodError

我们可以观察到在前面的4.1.9.Final这个版本居然是红色(没有被使用),难道是因为4.0.56这个jar包是在后面被引入的所以覆盖了前面的jar包吗?

android guava jar包冲突 jar包冲突原因_jar_04


android guava jar包冲突 jar包冲突原因_maven_05


我们发现虽然改变了依赖顺序但是还是4.0.56这个版本的jar包被使用,所以上面猜测是错误的。下面解释原因:

maven默认使用jar包策略

  • 短路径优先
A-->B-->C-->D(1.0.1)
E-->F-->D(1.0.2)

依赖A时和依赖E时都会引入依赖D,但是D的版本号不同,此时遵循maven默认使用jar包的策略程序会使用D(1.0.2)这个jar包。因为他的路径为2但是A下面Djar包的路径为3。

  • 声明优先原则
A-->B-->C-->T(1.0.1)
E-->F-->R-->T(1.0.2)

当路径一样时(且路径不为0,即不是在pom文件里面直接引用相同jar包的不同版本),短路径优先原则失效,此时应该遵循声明优先原则,谁在前面被引用就使用谁。上面会使用T(1.0.1)这个版本。

  • 直接引用覆盖原则
    在pom文件直接引入两个不同版本的jar包时程序会使用在后面引入的那个版本的jar包,因为前面引入的那个jar包被覆盖了。

解决方法

排除掉不需要的版本jar包,手动排除示例:

android guava jar包冲突 jar包冲突原因_java_06


使用maven helper排除示例:

android guava jar包冲突 jar包冲突原因_java_07


选择不需要的jar包版本右键然后选择exclude

特殊情况
开发过程中遇到过一次这样的情况:
某个jar包低版本差了一个程序需要的类程序提示:

Caused by: java.lang.ClassNotFoundException

高版本有这个类但是另一个类里面的方法随着版本的迭代没有了,程序提示:

Caused by:java.lang.NoSuchMethodError

上面这种情况好像去掉任意一个jar包(或者说使用任意一个jar包)程序都会报错,这个时候该怎么办呢。

解决思路
在将jar包的低版本和高版本之间的几个版本都用过之后发现没有一个版本能解决上面的问题,此时改变思路,这个jar包改变了没用那就去找找看是哪些jar包会用到这个jar包,然后将其它jar包的版本替换成高版本(低版本也行),问题得以解决。