如何解决包冲突问题

下面举一个包冲突的例子:java

你引用了 2 个三方包 a.jar 和 b.jar , a.jar 中又引用了一个 c.jar ,假设 c.jar 的版本号为 version-1, b.jar 中也引用了 c.jar ,假设这里的 c.jar 相对于 a.jar 中的 c.jar 为较高版本,记为 version-2 , b.jar 中某个类引用了 c.jar 的类 classA 中的方法 method A() ,而且该方法只存在于高版本的 c.jar(version-2) 的类 classA 中,而不存在c.jar(version-1) 的类 classA 中。eclipse

当系统编译加载时,系统可能编译加载 c.jar(version-1) ,也可能编译加载 c.jar(version-2) ,当编译加载c.jar(version-2) 时,因为不少 jar 包都支持向下兼容,即高版本兼容低版本,所以不论 a.jar 调用 c.jar 仍是 b.jar 调用 c.jar 通常都不会出问题。但若是此时恰好应用编译加载的是 c.jar(version-1) 中的类 classA 时,那么 b.jar 调用Method A() 时便会报上述错误,由于 Method A() 函数只存在于高版本的 c.jar 中,而此时系统编译加载的倒是低版本的 c.jar 。jvm

jar包冲突常见的异常为找不到类(java.lang.ClassNotFoundException)、找不到具体方法(java.lang.NoSuchMethodError)、字段错误( java.lang.NoSuchFieldError)或者类错误(java.lang.LinkageError)maven

常见的解决方法以下:ide

一、首先作法是打出工程文件的依赖树,将根据jar包依赖状况断定是否是同一个jar包依赖了多个版本,若是确认问题所在,直接exclusion其中错误的jar包便可;函数

二、若是经过看依赖树不能肯定具体冲突的jar包,可使用添加jvm参数的方式启动程序,将类加载的具体jar信息打印出来;-verbose:class;google

三、通过上述步骤基本就能够解决jar包冲突问题,具体的问题要具体分析,当问题不可重现时上述方法均不会奏效。idea

排包方法:spa

<dependency>
  <groupId>com.know.diamond</groupId>
  <artifactId>diamond-sdk</artifactId>
  <version>2.0.5</version>
  <exclusions>
      <exclusion>
        <groupId>com.google.collections</groupId>
         <artifactId>google-collections</artifactId>
   </exclusion>
   </exclusions>
</dependency>

当遇到jar包冲突时,咱们首先肯定是哪一个jar包冲突了,这个很容易,看咱们调用的类或方法,是属于哪一个Jar包。而后就是要找出冲突了,我这里使用命令code

mvn dependency:tree -Dverbose -Dincludes=<groupId>:<artifactId>

填写上Jar包的groupId和artifactId,能够只有一个,可是中间的冒号不要少,这样就会输出依赖树,并且是仅包含这个Jar包的依赖树,这样那些地方依赖了这个Jar包的那个版本就一目了然了。
例如,个人项目中notify-common包存在冲突,咱们使用命令
mvn dependency:tree -Dverbose -Dincludes=:notify-common
获得依赖树输出

[INFO] com.taobao.wlb:bis-server:war:1.0-SNAPSHOT
[INFO] +- com.taobao.wlb:bis-core:jar:1.0-SNAPSHOT:compile
[INFO] |  \- com.taobao.logistics:schedule-client:jar:1.1.1:compile
[INFO] |     \- (com.taobao.notify:notify-common:jar:1.8.15:compile - omitted for conflict with 1.8.19.26)
[INFO] \- com.taobao.notify:notify-tr-client:jar:1.8.19.26:compile
[INFO]    +- com.taobao.notify:notify-common:jar:1.8.19.26:compile
[INFO]    \- com.taobao.notify:notify-remoting:jar:1.8.19.26:compile
[INFO]       \- (com.taobao.notify:notify-common:jar:1.8.19.26:compile - omitted for duplicate) 

看一下依赖树中全部的叶子节点就是全部的notify-common包,咱们能够看到咱们依赖的bis-core中依赖了schedule-client包,它依赖了一个notify-common包,版本是1.8.15,第四行的后面也提示了这个包同其余包有冲突
- omitted for conflict with 1.8.19.26)。而咱们的系统依赖的notify-tr-client包所依赖的版本是1.8.19.26,因而咱们知道是这里冲突了,在POM排除掉依赖,OK了。

说明

这里咱们对咱们执行的命令作一个简单的说明。
mvn dependency:tree -Dverbose -Dincludes=<groupId>:<artifactId>
第一部分mvn dependency:tree是maven依赖的分析命令,做用是对咱们的项目的依赖进行分析,并输出项目依赖树。

第二部分-Dverbose的做用是添加了verbose一个环境变量,起的做用是在分析项目依赖时输出明细,这样项目中依赖的全部引用都会被输出出来,包含了全部的间接引用,会有不少不少,咱们只须要咱们要找的,因此就须要第三个参数了。

第三部分-Dincludes=<groupId>:<artifactId>的做用就是进行过滤,只包含咱们想要的依赖的依赖时,排除掉其它不须要的,依赖树的全部叶子节点就是咱们的找的依赖包。其中的groupId和artifactId能够只填写一个,为了保证准确性,通常都会填两个(填写时不包括尖括号)。

其余方法:

一、对于maven工程,个人办法是使用eclipse来解决,点开pom.xml,切换到hierarchy dependency,右上角搜索对应的包,能够清晰地看到冲突版本

二、可使用idea,在pom.xml中右单击 选择Diagrams-》show dependencies

三、mvn dependency:tree -Dverbose > tree.log 直接输出冲突的jar文件