通过IDEA快速定位和排除依赖冲突
前言
我们程序员在开发的时候经常会遇到各种各样的 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 包冲突的主要原因就是依赖的版本冲突。
异常发生
项目中需要导出报表,技术选型的时候,一般是选用 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包依赖冲突所导致的。
异常定位
那我们来定位下是哪个 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 包就可以了。如何排除呢?
排除冲突
我们在 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的功能还是很强大的。
总结
很多时候的 jar 包冲突,有些是我们很容易排除,例如在pom.xml 中我们就可以发现一些重复引入,但是版本不相同的依赖。还有一些是其他依赖传递依赖进来的,我们在 pom.xml 文件中不能很直观的发现,这时候我们借助工具可以发现这种冲突的依赖。
但是还有一些是更隐秘的冲突,就像本文中描述的依赖冲突,这时候我们需要分析异常信息,并定位冲突的原因和找到具体冲突的依赖引入,最后将它排除就可以了。
本文比较详细的介绍了异常的分析和冲突的定位,以及最后的排除。类似的依赖冲突基本都可以参考上述的方式进行排查,希望通过本篇文章对大家解决项目中依赖冲突有所帮助。
通过IDEA快速定位和排除依赖冲突的更多相关文章
- maven依赖传递和排除依赖冲突
1 依赖的传递 假如 A项目 依赖 a.jar 1.0.1,b.jar 1.0.1,没有直接依赖c.jar 1.0.1,但是b.jar 1.0.1依赖了c.jar 1.0.1,可以说A项目间接依赖了c ...
- 如何快速的解决Maven依赖冲突
为什么会出现依赖冲突 首先要说明Maven的依赖管理,具体的可以参考这边 Maven学习——依赖管理 这篇文章,maven在依赖冲管理中有一下几个原则. 依赖是使用Maven坐标来定位的,而Maven ...
- Maven依赖传递、依赖传递排除、依赖冲突
转载请注明原文地址:http://www.cnblogs.com/ygj0930/p/6628429.html 一:Maven依赖传递 假如有Maven项目A,项目B依赖A,项目C依赖B.那么我们可 ...
- Arthas 实战,助你解决同名类依赖冲突问题
上篇文章中,小黑哥分析 Maven 依赖冲突分为两类: 项目同一依赖应用,存在多版本,每个版本同一个类,可能存在差异. 项目不同依赖应用,存在包名,类名完全一样的类. 第二种情况,往往是这个场景,本地 ...
- gradle依赖冲突
# 如何定位依赖冲突? 了解如何定位依赖冲突问题之前,我们先手动制造一个依赖冲突. 我们在 build.gradle 引入两个依赖库: compile 'org.hibernate:hibernate ...
- Java开发学习(三十五)----SpringBoot快速入门及起步依赖解析
一.SpringBoot简介 SpringBoot 是由 Pivotal 团队提供的全新框架,其设计目的是用来简化 Spring 应用的初始搭建以及开发过程. 使用了 Spring 框架后已经简化了我 ...
- 企业IT管理员IE11升级指南【16】—— 使用Compat Inspector快速定位IE兼容性问题
企业IT管理员IE11升级指南 系列: [1]—— Internet Explorer 11增强保护模式 (EPM) 介绍 [2]—— Internet Explorer 11 对Adobe Flas ...
- maven 检查依赖冲突和版本冲突
maven 检查依赖冲突和版本冲突 在项目发布的时候,一般都需要进行依赖冲突检查或者重复类的检查,这个时候我一般会使用下面的两个命令: 1 2 3 mvn -U clean package - ...
- 32位汇编第六讲,OllyDbg逆向植物大战僵尸,快速定位阳光基址
32位汇编第六讲,OllyDbg逆向植物大战僵尸,快速定位阳光基址 一丶基址,随机基址的理解 首先,全局变量的地址,我们都知道是固定的,是在PE文件中有保存的 但是高版本有了随机基址,那么要怎么解决这 ...
随机推荐
- 问题TypeError: __init__() takes 1 positional argument but 2 were given解决方案
在搭建自动化框架时,遇到一个问题,如下图: 根据报错的意思,应该是__init__函数的问题, 位置应该是HomePage文件 立马去查看一下文件,如图: 原来是因为的粗心大意__init__(sel ...
- Hyper-V虚拟机win7网络红叉,无法上网解决方法
之前一直都是玩Vmware虚拟机,后来win8之后的系统有Hyper-V虚拟机就开始接触了. Windows 中内置的Hyper-V管理器可以说是给很多人带来了惊喜!至少运行的流畅程度要比Vmware ...
- OFD电子文档阅读器功能说明(采用WPF开发,永久免费)
特别说明 ofd阅读器开发语言为c#,具有完全自主产权,没有使用第三方ofd开发包.可以根据你的需求快速定制开发.本阅读器还在开发完善阶段,如有任何问题,可以联系我QQ:13712486.博客:htt ...
- 刨ThreadLocal的坟
ThreadLocal是大家比较常用到的,在多线程下存储线程相关数据十分合适.可是很多时候我们并没有深入去了解它的原理. 首选提出几个问题,稍后再针对这些问题一一解答. 提到ThreadLocal,大 ...
- Cohen-Sutherland算法
Cohen-Sutherland算法 本算法又称为编码裁剪算法,算法的基本思想是对每 条直线段分三种情况处理: (1)若点p1和p 2完全在裁剪窗口内 “简取”之 (2)若点p1(x1,y1)和p2( ...
- Jenkins基本使用
Jenkins安装 安装基本上属于傻瓜式安装了 选择安装路径不要包含中文 点击install 找到默认密码 选择插件安装 点击无,然后再选择安装 创建一个管理员 Jenkins配置任务 新建工程 输入 ...
- 02--Java Jshell的使用 最适合入门的Java教程
JShell JShell目标 Java Shell 工具(简称:JShell)是一个用于学习Java编程语言和构建Java代码原型的交互式工具.JShell是一个Read-Evaluate-Prin ...
- 解决Zend OPcache huge_code_pages: mmap(HUGETLB) failed: Cannot allocate memory报错
前几日看到鸟哥介绍的 <让你的PHP7更快之Hugepage>, 于是想试试手给服务器加上,参照格式安装好扩展,调整好配置文件,然后重启php-fpm,结果启动一直报Zend OPcach ...
- 在已有 Windows10 系统的基础上,安装 Ubuntu17.10 系统(新版 BIOS)
1.第一步,下载Ubuntu系统镜像 2.第二步,制作启动U盘,使用UltralSO,步骤:打开文件——选择iso文件——启动——写入硬盘映像——选择U盘——写入 3.第三步,分区,在Windows徽 ...
- 网络攻防实验任务三_(2)X-Scan通用漏洞扫描实验
首先在宿主机中打开xscan_gui.exe,结果系统直接将它删掉了. 大概是因为开了防火墙的缘故. 于是我在win7虚拟机中运行这个程序. 并且关闭防火墙,在win7中可以运行 我再试了一下win1 ...