【Maven】——Jar包冲突解决⽅案调研
⼀.jar包冲突的
Java 应⽤程序因某种因素,加载不到正确的类⽽导致其⾏为跟预期不⼀致。
⼆. jar包冲突的两种情况
第⼀类jar包冲突问题(同⼀jar包版本不同)
1. 应⽤程序依赖的同⼀个 Jar 包出现了多个不同版本,并选择了错误的版本⽽导致 加载不到需要的类或加载了错误版本的类。
2. 出现该问题的三个必要条件:
依赖树中出现了同⼀个jar包的多个版本。
该jar包的多个版本之间接⼝发⽣了变化(类名,⽅法签名变化,⽅法⾏为变化)
的仲裁机制选择了错误的版本
第⼆类jar包冲突问题(不同jar包的同⼀类版本不同)
1. 同样的类(类的全限定名完全⼀样)出现在多个不同的依赖 Jar 包中,即该类有多个版本,并由于 Jar 包加载的先后顺序(Maven的
路径最短和覆盖优先原则)导致 JVM 加载了错误版本的类。如:假设有 A 、 B 、 C 三个jar包,由于 Jar 包依赖的路径长短、声明的先后顺序或 的⽂件加载顺序等原因, ⾸先从 Jar 包 A 中加载了该类后,就不会加载其余 Jar 包中的这个类了。
2. 出现该问题的三个必要条件:
同⼀类M出现在了两个(或两个以上)不同的jar包A、B中。
类M在A、B中有差异,⾏为不同。
加载的类M不是我们想要的。
三.解决⽅案
⽅法⼀:⼿动排查
1. 根据异常堆栈信息确定导致冲突的类名。
2. 通过mvn dependency:tree -Dverbose -Dincludes=: 查看是哪个地⽅引⼊的jar包的版本。
3. 如果是第⼀类 Jar 包冲突,则可⽤ 排除不需要的 Jar 包版本或者在依赖 **** 中申明版本。
4. 如果是第⼆类Jar包冲突,如果可以排除,则⽤ 排掉不需要的那个 Jar 包,若不能排,则需考虑 Jar 包的升级或换个别的 Jar 包。
⽅法⼆:通过⾃定义ClassLoader实现隔离
在 Java 中隔离容器的实现 中提到了将每个jar包视为多个bundle,通过⾃定义claoader隔离运⾏,并且还可以实现多个jar包共享⼀个类。 该Demo通过启动⼀个KContainer类运⾏,KContainer类中主要包含⼀个BundleList和SharedClassList。每⼀个Bundle代表⼀个jar包或者class路径,Bundle类包含⼀个⾃定义的BundleClassLoader类(继承UrlClassLoader),由于不同
maven打包本地jar包
BundleBundleClassLoader不同,可以实现 隔离运⾏ ,⽽这个BundleClassLoader需要传⼊⼀个SharedClassList,classloader 在加载⼀个类时,如果没有加载到,则可以从外部传进来的SharedClassList中加载,这样就实现了多个jar包共享⼀个类 。需要共享出去给别⼈⽤的类可以通过在类路径下通过⼀个properties⽂件指定,在loadBundle的时候加载进SharedClassList。
protected Class<?> findClass(String name) throws ClassNotFoundException {
logger.debug(“try find class {}”, name);
Class<?> claz = null;
try {
claz = super.findClass(name);
} catch (ClassNotFoundException e) {
claz = null;
}
if (claz != null) {
logger.debug(“load from class path for {}”, name);
return claz;
}
/
/如果没有加载到,从共享的类中加载
claz = (name);
if (claz != null) {
logger.debug(“load from shared class for {}”, name);
return claz;
}
logger.warn(“not found class {}”, name);
throw new ClassNotFoundException(name);
}
⽅法三:轻量级隔离容器SOFAArkSOFAArk
同样也是使⽤不同的类加载器加载冲突的三⽅依赖包,进⽽做到在同⼀个应⽤运⾏时共存。 SOFAArk
通过Ark Plugin区分应⽤中哪些依赖包是需要单独的类加载器加载 。借助 SOFABoot 官⽅提供的 maven 打包 ,可以把若⼲普通的 JAR 包打包成 Ark Plugin 供应⽤依赖或者把普通的 Java 模块改造成 Ark Plugin。应⽤使⽤添加 maven 依赖的⽅式引⼊ Ark Plugin,运⾏时,SOFAArk 框架会⾃动识别应⽤的三⽅依赖包中是否含有 Ark Plugin,进⽽使⽤单独的类加载器加载。其运⾏时逻辑图如下:
1. SOFAArk 容器处于最底层,负责启动应⽤。
2. 每个 Ark Plugin 都由 SOFAArk 容器使⽤独⽴的类加载器加载,相互隔离。
3. 应⽤业务代码及其他⾮ Ark Plugin 的普通三⽅依赖包,统称为 Ark Biz。需要依赖下层的Ark Plugin。
在Ark Plugin的POM⽂件中,会 导出类和导⼊类的配置。导出类即把 Ark Plugin 中的类导出给 Ark Biz 和其他 Ark Plugin 可见。对于 Ark Plugin 来说,如果需要使⽤其他 Ark Plugin 的导出类,必须声明为⾃⾝的导⼊类。
⽅法四:阿⾥的Pandora隔离容器
阿⾥的Pandora是闭源的,⽹上资料⽐较少。 可以从阿⾥的⼀次演讲PPT上得知,Pandora仍然是基于ClassLoader实现的 Pandora 这类的隔离容器的缺点:
1. 使⽤⽅式复杂,难以理解。
2. 启动慢,⽤户⽆法按需选择
3. 困难
4. 部署和运维困难

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。