两类问题,都会导致jvm加载不到正确的类,那么行为就和预期不一样

  • 第一类jar冲突问题
    应用程序依赖的同一个jar包出现了多个不同的版本,并选择了错误的版本(某个类在这个版本中不存在或者类的行为不一致)导致JVM加载到了错误的类。
  • 第二类jar冲突问题
    同样的类(类的全限定名完全一样)出现在多个jar中,即该类有多个版本,由于jar包加载先后顺序导致JVM加载了错误的版本

第一类jar包问题

随着Jar包迭代升级,我们所依赖的开源的或公司内部的Jar包工具都会存在若干不同的版本,而版本升级自然就避免不了类的方法签名变更,甚至于类名的更替,而我们当前的应用程序往往依赖特定版本的某个类 M ,由于maven的传递依赖而导致同一个Jar包出现了多个版本,当maven的仲裁机制选择了错误的版本时,而恰好类 M在该版本中被去掉了,或者方法签名改了,导致应用程序因找不到所需的类 M或找不到类 M中的特定方法,就会出现第一类Jar冲突问题

三个必要条件:

  • 由于maven的传递依赖导致依赖树中出现了同一个Jar包的多个版本
  • 该Jar包的多个版本之间存在接口差异,如类名更替,方法签名更替等,且应用程序依赖了其中有变更的类或方法
  • maven的仲裁机制选择了错误的版本

第二类jar包问题

 同样的类出现在了应用程序所依赖的两个及以上的不同Jar包中,这会导致什么问题呢?我们知道,同一个类加载器对于同一个类只会加载一次(多个不同类加载器就另说了,这也是解决Jar包冲突的一个思路,后面会谈到),那么当一个类出现在了多个Jar包中,假设有 ABC 等,由于Jar包依赖的路径长短、声明的先后顺序或文件系统的文件加载顺序等原因,类加载器首先从Jar包 A 中加载了该类后,就不会加载其余Jar包中的这个类了,那么问题来了:如果应用程序此时需要的是Jar包 B 中的类版本,并且该类在Jar包 AB 中有差异(方法不同、成员不同等等),而JVM却加载了Jar包 A 的中的类版本,与期望不一致,自然就会出现各种诡异的问题。

三个必要条件

  • 同一个类 M 出现在了多个依赖的Jar包中,为了叙述方便,假设还是两个: AB
  • Jar包 AB 中的该类 M 有差异,无论是方法签名不同也好,成员变量不同也好,只要可以造成实际加载的类的行为和期望不一致都行。如果说Jar包 AB 中的该类完全一样,那么类加载器无论先加载哪个Jar包,得到的都是同样版本的类 M ,不会有任何影响,也就不会出现Jar包冲突带来的诡异问题。
  • 加载的类 M 不是所期望的版本,即加载了错误的Jar包

解决方案

  • maven exclude排除jar,选择合适版本
  • 自定义类加载器,打破双亲委派模型(比较著名的是pandora)