• 如何解决包冲突问题


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

    你引用了 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 中。

    当系统编译加载时,系统可能编译加载 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 。

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

    常见的解决方法如下:

    1、首先做法是打出工程文件的依赖树,将根据jar包依赖情况判定是不是同一个jar包依赖了多个版本,如果确认问题所在,直接exclusion其中错误的jar包即可;

    2、如果通过看依赖树不能确定具体冲突的jar包,可以使用添加jvm参数的方式启动程序,将类加载的具体jar信息打印出来;-verbose:class;

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

    排包方法:

    <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包。然后就是要找出冲突了,我这里使用命令

    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可以只填写一个,为了保证准确性,一般都会填两个(填写时不包括尖括号)。

    其他方法:

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

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

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

  • 相关阅读:
    当我们开发一个接口时需要注意些什么
    一条查询语句在MySQL服务端的执行过程
    痞子衡嵌入式:基于恩智浦i.MXRT1060的MP4视频播放器(RT-Mp4Player)设计
    痞子衡嵌入式:基于恩智浦i.MXRT1010的MP3音乐播放器(RT-Mp3Player)设计
    《痞子衡嵌入式半月刊》 第 18 期
    痞子衡嵌入式:MCUBootUtility v2.4发布,轻松更换Flashloader文件
    华为HMS Core助力开发者打造精品应用,共创数智生活
    HMS Core 6.0即将发布 加码应用生态升级
    华为开发者联盟生态市场企业特惠GO第1期—应用软件专题
    卡片跳转快应用指定页面,如何点返回直接退出快应用回到卡片
  • 原文地址:https://www.cnblogs.com/songshu120/p/6164114.html
Copyright © 2020-2023  润新知