依赖冲突了如何解决?

Posted androidstarjack

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了依赖冲突了如何解决?相关的知识,希望对你有一定的参考价值。

点击上方关注 “终端研发部”
设为“星标”,和你一起掌握更多数据库知识

作者 | jajian

链接 | cnblogs.com/jajian/p/11002521.html

0、前言

由于此订阅号换了个皮肤,系统自动取消了读者的公众号置顶。导致用户接受文章不及时。可以打开订阅号,选择置顶(标星)公众号,重磅干货,第一时间送达!

1、前言

我们程序员在开发的时候经常会遇到各种各样的 BUG 问题,其中大部分是业务逻辑异常,还有一些是代码书写不规范造成的异常。

例如:NullPointException(NPE),IndexOutOfBoundsException 等等,其实这些我们都好定位和修复。但是还有一些运行时异常定位起来是特别头疼的,那就是 jar 包冲突引起的异常。

一般程序在运行时发生类似于 java.lang.ClassNotFoundException,Method not found: '……',或者莫名其妙的异常信息,这种情况一般很大可能就是 jar包依赖冲突的问题引起的了。

至于为什么会发生 jar包依赖冲突?这种问题大致可以归纳为如下几个原因:

  • 版本不匹配,高版本依赖了低版本,或者低版本依赖了高版本。例如引入第三方库,但是第三方库基于的是 JDK7,而你们项目使用的是JDK8。

  • 重复引入不同版本jar包,造成使用错误。很多时候我们引入第三方轮子,它们依赖引入某个基础工具使用的是 v 1.0 的 jar,但是我们项目中自己也引入了该 jar,但是版本是 v 2.3,这时就会造成项目中使用同一个组件但是依赖了两个不同版本的jar,冲突就会发生。

可以看到,其实总的来说 jar 包冲突的主要原因就是依赖的版本冲突。

2、异常发生

项目中需要导出报表,技术选型的时候,一般是选用 Apache POI,但是 POI 的使用方式比较基础,开发量大,容易出现内存溢出的问题。

考虑到阿里开源了一套解析和生成Excel的工具 - EasyExcel,具有避免内存溢出OOM的情况发生,而且使用方便简单,所以就将它引入到了我们的项目中,具体的使用版本是 1.0.2。


 
<dependency>
   <groupId>com.alibaba</groupId>
    <artifactId>easyexcel</artifactId>
    <version>1.0.2</version>
</dependency>

而另一个模块需要使用 POI 的将 Word 转成 PDF 的功能,所以同时又引入了如下 POI 的依赖:


 
<!-- poi utils -->
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi</artifactId>
    <version>3.15</version>
</dependency>
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-ooxml</artifactId>
    <version>3.15</version>
</dependency>

我们从 Maven Repository 可以发现,阿里 EasyExcel 1.0.2 依赖的 POI 也是 3.15,所以照理说应该是没问题的。

但是在接口调试的时候还是出问题了,而且异常信息很奇怪,不是看一眼就能知道问题原因的并解决的。


 
Caused by: java.lang.AbstractMethodError: org.apache.xerces.dom.DocumentImpl.getXmlStandalone()Z
    at com.sun.org.apache.xalan.internal.xsltc.trax.DOM2TO.setDocumentInfo(DOM2TO.java:377)
    at com.sun.org.apache.xalan.internal.xsltc.trax.DOM2TO.parse(DOM2TO.java:131)
    at com.sun.org.apache.xalan.internal.xsltc.trax.DOM2TO.parse(DOM2TO.java:98)
    at com.sun.org.apache.xalan.internal.xsltc.trax.TransformerImpl.transformIdentity(TransformerImpl.java:693)
    at com.sun.org.apache.xalan.internal.xsltc.trax.TransformerImpl.transform(TransformerImpl.java:737)
    at com.sun.org.apache.xalan.internal.xsltc.trax.TransformerImpl.transform(TransformerImpl.java:351)
    at org.apache.poi.openxml4j.opc.StreamHelper.saveXmlInStream(StreamHelper.java:80)
    at org.apache.poi.openxml4j.opc.internal.marshallers.ZipPartMarshaller.marshallRelationshipPart(ZipPartMarshaller.java:181)
    at org.apache.poi.openxml4j.opc.ZipPackage.saveImpl(ZipPackage.java:560)
    at org.apache.poi.openxml4j.opc.OPCPackage.save(OPCPackage.java:1557)
    at org.apache.poi.POIXMLDocument.write(POIXMLDocument.java:248)
    at org.apache.poi.xssf.streaming.SXSSFWorkbook.write(SXSSFWorkbook.java:941)
    at com.alibaba.excel.write.ExcelBuilderImpl.finish(ExcelBuilderImpl.java:64)
    at com.alibaba.excel.ExcelWriter.finish(ExcelWriter.java:95)
    at com.pingan.haofang.creams.common.utils.ExcelUtil.writeExcel(ExcelUtil.java:71)
    ......
    ... 65 common frames omitted

提取关键信息,可以看到错误类型 java.lang.AbstractMethodError,这个错误类型望名知义:抽象方法错误。这种类型的错误和我们上面说的 ClassNotFoundException 类似,很大可能就是 Jar包依赖冲突所导致的。

3、异常定位

那我们来定位下是哪个 jar 包冲突了,只需要将冲突的 jar 包排除掉,留下正确的就可以了。

我们可以看到错误类型是 java.lang.AbstractMethodError,错误类型后面是具体的错误信息描述 :org.apache.xerces.dom.DocumentImpl.getXmlStandalone()Z,意思是在包 org.apache.xerces.dom 下的类DocumentImpl它的方法getXmlStandalone()调用出现了错误。

那么具体是谁在调用呢?我们在异常信息的紧密下一行可以看到如下这一行代码:


 
at com.sun.org.apache.xalan.internal.xsltc.trax.DOM2TO.setDocumentInfo(DOM2TO.java:377)

在包路径 com.sun.org.apache.xalan.internal.xsltc.trax 下,DOM2TO 类代码的的第377行,有个setDocumentInfo方法,我们鼠标左键点进去,在该行加个 Debug 断点。

我们发现这个 DOM2TO 类是 JDK1.8中 rt.jar 包里面的,具体类路径如下:

通过断点调试得知,这个 document 对象是 DocumentImpl 实例,

这个DocumentImpl 的真实路径也是 JDK1.8中 rt.jar 包里面的,它是 CoreDocumentImpl 的子类,CoreDocumentImpl 是接口Document 的实现类。


 
package com.sun.org.apache.xerces.internal.dom;


public class DocumentImpl
    extends CoreDocumentImpl
    implements DocumentTraversal, DocumentEvent, DocumentRange {


    ......
}

CoreDocumentImpl


 
package com.sun.org.apache.xerces.internal.dom;


public class CoreDocumentImpl
        extends ParentNode implements Document {


       ......
}

我们在 CoreDocumentImpl 类中第983行发现了getXmlStandalone方法。

这时报错原因赤条条的摆在我们面前了,显而易见,DOM2TO类中 setDocumentInfo 方法的参数 Document 是属于 JDK1.8 中 rt.jar 包下类路径 com.sun.org.apache.xerces.internal.dom 下的实现类 DocumentImpl。而我们报错的信息提示中是:


 
Caused by: java.lang.AbstractMethodError: org.apache.xerces.dom.DocumentImpl.getXmlStandalone()Z

这个 org.apache.xerces.dom.DocumentImpl 明显不属于我们 JDK1.8 的 rt.jar 包,而且也没有 getXmlStandalone 这个方法。

所以得知,我的项目中 jar 包依赖冲突了,我们只需要排除掉 org.apache.xerces.dom.DocumentImpl 所属的 jar 包就可以了。如何排除呢?

4、排除冲突

我们在 IDEA 中双击 Shift 键,输入 DocumentImpl,得到如下结果:

可以发现,这里有两个 CoreDocumentImpl,一个是我们的 JDK1.8的,一个是属于 xerce的,而且确实在依赖的 maven jar 包中发现了 xercesImpl-2.4.0.jar,这个 jar包就是需要排除的 jar包。

发现了冲突的 jar包,我全局搜索关键字 xerces,并没有发现哪一个 pom 中有依赖的代码,所以很可能是其他的 jar 包传递依赖进来的。

我们借助 IDEA 的 maven 工具,在 maven 栏右键项目模块,选择 show Dependencies 或 Ctrl + Shift + Alt + U,这时候会展示当前模块的 jar 包依赖图,如下:

虽然这里展示了很多冲突的jar包,其中红线连接的就是冲突的jar 包,但是我们 Ctrl + F 查询 xerces 还是没有结果。

所以我们需要额外的方式来解决,这时我想到了 IDEA 有个插件 Maven Helper,具体的插件下载可以参考前面的内容,下载好插件后,我们打开 pom.xml 文件,在pom.xml 文件的左下方有个 Dependency Analyzer,我们点击之后显示如下:

  • Conflicts:展示所有冲突。

  • All Dependencies as List:以列表的方式展示所有依赖。

  • All Dependencies as Tree:以树形的方式展示所有依赖。

我们输入 xerces,选择以树形展示所有依赖,得到如下的信息显示。

清晰明了,原来这个罪魁祸首是被 file-web-sdk 带进来的,我们右键选择 Jump To Source或者 F4 定位到这个 jar 在 pom.xml 的依赖引入位置,如下图所示,我们通过 exclusion 标签排除 xercesImpl 的引入即可。


 
<dependency>
    <groupId>com.xx.xx.gov.fileservice</groupId>
    <artifactId>file-web-sdk</artifactId>
    <exclusions>
        <exclusion>
            <groupId>xerces</groupId>
            <artifactId>xercesImpl</artifactId>
        </exclusion>
    </exclusions>
</dependency>

再次启动项目,测试接口发现功能正常了,整个排查过程也就结束了,IDEA的功能还是很强大的。

5、总结

很多时候的 jar 包冲突,有些是我们很容易排除,例如在pom.xml 中我们就可以发现一些重复引入,但是版本不相同的依赖。还有一些是其他依赖传递依赖进来的,我们在 pom.xml 文件中不能很直观的发现,这时候我们借助工具可以发现这种冲突的依赖。

但是还有一些是更隐秘的冲突,就像本文中描述的依赖冲突,这时候我们需要分析异常信息,并定位冲突的原因和找到具体冲突的依赖引入,最后将它排除就可以了。

本文比较详细的介绍了异常的分析和冲突的定位,以及最后的排除。类似的依赖冲突基本都可以参考上述的方式进行排查,希望通过本篇文章对大家解决项目中依赖冲突有所帮助。

BAT等大厂Java面试经验总结


 

 

想获取 Java大厂面试题学习资料

扫下方二维码回复「BAT」就好了

回复 【加群】获取github掘金交流群
回复 【电子书】获取2020电子书教程
回复 【C】获取全套C语言学习知识手册
回复 【Java】获取java相关的视频教程和资料
回复 【爬虫】获取SpringCloud相关多的学习资料
回复 【Python】即可获得Python基础到进阶的学习教程
回复 【idea破解】即可获得intellij idea相关的破解教程
关注我gitHub掘金,每天发掘一篇好项目,学习技术不迷路!


回复 【idea激活】即可获得idea的激活方式

回复 【Java】获取java相关的视频教程和资料

回复 【SpringCloud】获取SpringCloud相关多的学习资料

回复 【python】获取全套0基础Python知识手册

回复 【2020】获取2020java相关面试题教程

回复 【加群】即可加入终端研发部相关的技术交流群

阅读更多

为什么HTTPS是安全的

因为BitMap,白白搭进去8台服务器...

《某厂内部SQL大全 》.PDF

字节跳动一面:i++ 是线程安全的吗?

大家好,欢迎加我微信,很高兴认识你!

在华为鸿蒙 OS 上尝鲜,我的第一个“hello world”,起飞!

相信自己,没有做不到的,只有想不到的

在这里获得的不仅仅是技术!


如果喜欢就给个“在看

以上是关于依赖冲突了如何解决?的主要内容,如果未能解决你的问题,请参考以下文章

如何解决传递依赖冲突问题?

如何解决包冲突问题

终极方案:快速解决Android项目依赖冲突

依赖冲突了如何解决?

如何删除maven中冲突的jar包

如何解决 Mariadb 与 mysql 的冲突以安装 mySQL-python 依赖项