包冲突的解决办法

注意所有关于maven的pom文件的改动,最后都要reimport一下,IDE会强制根据新的pom.xml设置重新分析并加载依赖类包,以得到和pom.xml设置相同的依赖。(这一步非常重要哦,经常项目组pom.xml是相同的,但是就是有些人可以运行,有些人不能运行,俗称人品问题,其实都是IDE的缓存造成的了 )

包冲突的现象

运行时异常 NoSuchMethodError 就是典型包冲突异常,编译的时候并不会报错,

往往在运行的时候才会暴露问题,没有做充分验证会导致程序出现无法预知的返回结果。
运行时抛出 NoSuchMethodError 错误的根本原因就是: 应用程序直接或间接依赖了同一个类的多个版本,

并且在运行时执行了缺少方法的版本。 如下图所示:

为什么同一个 Class 会出现多个版本?

导致 Java Class 出现多版本的原因,可以归纳为以下几类:

  • JDK 版本不一致。 常见于编译打包环境使用高版本 JDK 开发与打包,而实际运行环境的 JDK 版本较低。例如,本地项目环境 JDK 版本为 1.7,调用 Character.isAlphabetic() 方法判断当前字符是否为字母;而线上环境 JDK 版本为 1.6,在运行期间就会抛出 NoSuchMethodError 错误。

  • SNAPSHOT 版本不一致。 常见于本地更新 SNAPSHOT 版本后,没有执行 mvn clean deploy 部署,导致线上环境运行时仍然引用了旧版本的 SNAPSHOT 包。

  • Maven 依赖生命周期为 provided。 常见于本地依赖的某组件生命周期为 provided,所声明版本仅用于本地编译打包,而线上运行时会通过其他依赖关系加载 Jar 包。

  • 同一个 Jar 包出现了多个版本。 常见于 Maven 依赖未显式指定版本号,导致间接依赖版本冲突,很容易引入低版本的 Jar 包。

  • 同一个 Class 出现在不同的 Jar 包中。 该问题常见于代码拷贝场景,比如基于开源版本定制了一些功能,使用了新的 Maven 坐标打包发布,此时 Maven 仲裁机制失效(非常隐蔽,难以排查)。由于 JVM 类加载器对于同一个类只会加载一次,最终加载的类实现受到 Jar 包依赖的路径、类声明的先后顺序或文件加载顺序等因素的影响,很可能出现不同机器加载的类实现不一致。 哪个版本的 Class 最终会被执行? 影响 Class 最终是否被执行的关键因素有两个:Maven 依赖仲裁机制和 JVM 类加载机制,如下图所示:

首先,Maven 依赖仲裁机制 决定了打包的优先级, 仲裁优先级"从高到低”如下所述:- 优先按照依赖管理 [dependencyManagement] 元素中指定的版本进行仲裁;- 若无版本声明,则按照 “短路径优先” 原则(Maven2.0)进行仲裁,即选择依赖树中路径最短的版本;-  若路径长度一致,则按照 “第一声明优先" 原则进行仲裁,即选择 POM 中最先声明的版本。

合理使用 Maven 依赖仲裁机制可以便捷的管理 Jar 包版本,而不合理的使用将导致多版本 Jar 冲突。

其次,JVM 类加载机制 决定了 Class 被加载到 JVM 的优先级, 如果同一个类出现在多个 Jar 包中,那么在双亲委派类加载机制下,加载该 Jar 包的类加载器层级越高,该 Jar 包越先被加载,它所包含的 Class 越先被执行,如上图所示:

  • 启动类加载器(Bootstrap ClassLoader)优先级最高,主要加载 JVM 运行时核心类,如 java.util、java.io等,这些类主要位于 $JAVA_HOME/lib/rt.jar 文件中。

  • 扩展类加载器(Extention ClassLoader)优先级次之,主要加载 JVM 扩展类,如 swing 组件、xml 解析器等,这些类主要位于 $JAVA_HOME/lib/ext/ 目录下的 Jar 包中。

  • 应用类加载器(Application ClassLoader),又称系统类加载器,优先级再次之,它会加载 Classpath 环境变量里定义的路径中的 Jar 包和目录,通常我们自己编写的代码或依赖的第三方 Jar 包都是由它来加载。

除了上述两种原因外,在同一个 ClassLoader 下,如果存在一个 Class 出现在不同的 Jar 包中,那么文件系统的文件加载顺序也可能会影响最终的加载结果。因此,应该尽量保证开发/测试/生产系统环境一致性。

如何解决 NoSuchMethodError 错误?

虽然抛出 NoSuchMethodError 错误的原因多种多样,但本质上是由于编译时类路径与运行时类路径不一致。因此,通用的定位思路可以归纳为以下 3 步:
1、定位异常 Class 的全限定类名与调用方,通常可以在应用日志抛出的异常堆栈中获取。
这里得到类名和方法名
2、定位异常 Class 的来源,

方法一

​ 可以通过 Arthas 等在线诊断工具反编译,如 jad com.xxx.AsyncAppender,获取该类运行时的源码、ClassLoader、Jar 包位置等信息。

如果应用程序启动失败,或者无法进行在线诊断,可以考虑添加 JVM 启动参数 -verbose:class 或 -XX:+TraceClassLoading,在日志中将输出每个类的加载信息,比如来自哪个 Jar 包。

方法二

也可以使用idea查找class

根据第一步找到的类名全局检索class文件,找到冲突的类

根据方法确认应该排除哪一个类,属于哪一个jar包

3、根据ClassLoader和jar包全路径名称等信息,判断是类加载、maven仲裁或其他原因,并对应的加以解决

解决方法

如果是同一个 Jar 包的多版本问题,可以在 Maven 标签中指定实际需要的版本,或者移除间接依赖中的低版本(提示: 执行 mvn dependency:tree 命令,可以查看 Maven 依赖拓扑关系)。

mvn dependency:tree
# 根据类名过滤得到冲突jar包是从哪一个jar包引入的
mvn dependency:tree -Dverbose -Dincludes=asm:asm

例如asm的jar包冲突

[INFO] --- maven-dependency-plugin:2.1:tree (default-cli) @ ridge-test ---
[INFO] com.ridge:ridge-test:jar:1.0.2-SNAPSHOT
[INFO] +- asm:asm:jar:3.2:compile
[INFO] \- org.unitils:unitils-dbmaintainer:jar:3.3:compile
[INFO]    \- org.hibernate:hibernate:jar:3.2.5.ga:compile
[INFO]       +- cglib:cglib:jar:2.1_3:compile
[INFO]       |  \- (asm:asm:jar:1.5.3:compile - omitted for conflict with 3.2)
[INFO]       \- (asm:asm:jar:1.5.3:compile - omitted for conflict with 3.2)
[INFO] ------------------------------------------------------------------------

对asm有依赖有一个直接的依赖(asm:asm:jar:3.2)还有一个传递进入的依赖(asm:asm:jar:1.5.3)

承上,假设我们不希望asm:asm:jar:1.5.3出现,根据分析,我们知道它是经由org.unitils:unitils-dbmaintainer:jar:3.3引入的,那么在pom.xml中找到这个依赖,做其它的调整:

<dependency>  <groupId>org.unitils</groupId>  <artifactId>unitils-dbmaintainer</artifactId>  <version>${unitils.version}</version>  <exclusions>  <exclusion>  <artifactId>dbunit</artifactId>  <groupId>org.dbunit</groupId>  </exclusion>  <!-- 这个就是我们要加的片断 -->  <exclusion>  <artifactId>asm</artifactId>  <groupId>asm</groupId>  </exclusion>  </exclusions>  </dependency>

再分析一下,你可以看到传递依赖没有了:

[INFO]
[INFO] --- maven-dependency-plugin:2.1:tree (default-cli) @ ridge-test ---
[INFO] com.ridge:ridge-test:jar:1.0.2-SNAPSHOT
[INFO] \- asm:asm:jar:3.2:compile
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS

其他 Jar 包冲突问题

本文介绍的 Jar 包冲突解决方法,除了解决 java.lang.NoSuchMethodError 以外,对其他相似问题也具备一定的参考价值。
例如 java.lang.ClassNotFoundException,即加载不到指定类,通常是 Maven 仲裁选错了版本,如本地开发阶段调用了 1.2.0 版本,而打包时采用了 1.0.0 版本的 Jar 包。这种就属于同一个 Class 出现在不同的 Jar 包问题,若可以排除,就用 排除该依赖;如不能排除,则考虑升级或替换为其他 Jar 包,或者考虑使用 ClassLoader 隔离技术,可参考 《如果jar包冲突不可避免,如何实现jar包隔离?》。
同理,java.lang.NoClassDefFoundError 和 java.lang.LinkageError 也可以基于上述思路进行排查。
此外,如果类和方法名都保持不变,但是内部实现有变化,在多版本冲突场景下,不会抛出异常,但程序行为跟预期不一致, 此时,也可以基于上述思路进行排查诊断。

参考博客:
https://blog.csdn.net/u014515854/article/details/80407024
https://developer.aliyun.com/article/714570

NoSuchMethodError 错误——包冲突解决办法相关推荐

  1. maven引入hadoop_Maven引入hadoop依赖包出错解决办法

    错误: ArtifactTransferException: Failure to transfer org.apache.hadoop:hadoop-hdfs:jar:2.6.0 from http ...

  2. 你真的知道 NoSuchMethodError 发生原因和解决办法吗

    点击上方"朱小厮的博客",选择"设为星标" 后台回复"加群"加入公众号专属技术群 来源:阿里巴巴中间件 当应用程序试图调用类(静态或实例)的 ...

  3. NoSuchMethodError 发生原因和解决办法

    当应用程序试图调用类(静态或实例)的指定方法,而该类已不再具有该方法的定义时,就会抛出 java.lang.NoSuchMethodError 错误.简单地说,就是同一个 Class 有多个版本的实现 ...

  4. 手机程序安装时几种有错误提示的解决办法

    错误提示一:证书过期 问题说明:软件证书过期. 解决办法:1:把手机时间调到证书的期限内(把手机时间往前调几个月)再安装,安装完毕后调回正确时间                            ...

  5. 在R语言环境中无法载入rJava包的解决办法

    问题描述: 安装包xlsx包后,运行library("xlsx")后弹出错误窗口: RGui (64-bit): Rgui.exe - 系统错误 无法启动此程序,因为计算机中丢失 ...

  6. SVN多用户开发 代码冲突解决办法

    [SVN多用户开发]代码冲突&解决办法 SVN是一款集中式的代码存储工具,可以帮助多个用户协同开发同一应用程序. 但是SVN不能完全代替人工操作,有时也需要程序员自己进行沟通确认有效的代码. ...

  7. eclipse下编写android程序突然不会自动生成R.java文件和包的解决办法

    eclipse下编写android程序突然不会自动生成R.java文件和包的解决办法 我的eclipse原来是好好的,什么问题都没有的,结果今天一打开新建一个android程序,发现工程里不会自动生成 ...

  8. eclipse android 不会自动生成R.java文件和包的解决办法

    eclipse下编写android程序突然不会自动生成R.java文件和包的解决办法 我的eclipse原来是好好的,什么问题都没有的,结果今天一打开新建一个android程序,发现工程里不会自动生成 ...

  9. ubuntu 16.04, conda不能安装、更新包的解决办法

    ubuntu 16.04, conda不能安装.更新包的解决办法 - truth的文章 - 知乎 https://zhuanlan.zhihu.com/p/36188524 昨天打算更新 pytorc ...

最新文章

  1. OVS端口镜像(十五)
  2. Linux 3.0发布
  3. DevOps笔记-04:DevOps工具和文化缺一不可
  4. Angular refreshView的执行原理
  5. sql慢查询问题排查
  6. 疑似OPPO Reno6系列新机通过工信部认证:配备6.43英寸屏 机身仅7.9mm
  7. MyBatis 源码自我解读
  8. [开源 .NET 跨平台 Crawler 数据采集 爬虫框架: DotnetSpider] [三] 配置式爬虫
  9. PHP开发网站全过程技术知识分析
  10. 深度残差网络(ResNet)详解与实现(tensorflow2.x)
  11. mysql sql语句集合
  12. 动态分配算法_【原创连载】算法素颜(第4篇):空间复杂度你真的懂了吗?
  13. USBCAN分析仪的配套CAN和CANFD综合测试软件LKMaster软件解决工程师CAN总线测试难题
  14. OSI 的七层模型有哪些?
  15. 【转】韩寒:跳出棋盘的棋子
  16. 电脑基础知识精选(硬件篇)
  17. wireshark 找不到wifi无线网卡的解决方法
  18. 贵州学计算机,在贵州省计算机学校学习计算机专业如何?
  19. 19、弱电工程综合布线报价多少钱一个点位?弱电入门学习
  20. JavaWeb专栏之(一):什么是JavaWeb?

热门文章

  1. sourceTree使用详解
  2. js中向数组中添加元素unshift() 方法
  3. 【Android Studio探索之路系列】之四:Android Studio快捷键
  4. HTML5--入门介绍
  5. Win11安装Android子系统
  6. 1000瓶药水,只有一瓶是有毒的,如何使用最少的小白鼠测出那瓶是毒药?
  7. IE8浏览器兼容问题(日常经验总结)
  8. 【Java面试题十】一套完整的java面试题
  9. Latex论文中用到的花体字
  10. 【OpenCV 例程300篇】208. Photoshop 对比度自动调整算法