Jar包冲突解决方案
背景介绍
项目名称:数据同步中心的HBaseReader插件迁移至玄武计算平台
项目背景:数据同步中心的开发环境为Spark 2.x + Scala 2.11,而玄武计算平台中的开发环境为Spark 3.0 + Scala 2.12,且开发环境所用HBase版本较低,所以在迁移中遇到了许多API错误和Jar包冲突问题
问题一,Spark版本升级导致以前的API调用方式不可用
旧版本调用在新版本中报错,如下图所示:
点进去查看该类发现在Spark 3.0 中该对象被私有化,无法调用
解决方案:本地构建一个DYSparkHadoopUtil,将用到的SparkHadoopUtil代码拷贝进去,并把调用的对象设为公有类型,在项目中import DYSparkHadoopUtil即可
问题二,Jar包冲突(可以掉的)
Jar包冲突产生的报错信息:NoClassDefFoundError、NoSuchMethodError、ClassNotFoundException
问题本质是由于JVM在加载Class文件的时候,加载了不一致的Class。可以手工剔除掉有问题的Maven依赖,但是当项目依赖较多时,人工寻找冲突的Jar包或者使用Maven自带的show dependencies会非常卡顿
解决方案:使用Maven Helper插件剔除(快速方便)
在Maven环境下Jar的加载顺序跟依赖树的节点位置相关,我们可以使用 mvn dependency:tree 来打印,或者在IDEA中安装 MavenHelper 插件来查看工程的依赖树,如下图:
定位到具体的冲突包后,利用Maven Helper插件将冲突Jar包剔除即可。
ps:依赖的优先级如下:
优先加载靠近根节点的依赖(层级浅的优先加载),优先加载在 pom.xml 中 元素内靠前的依赖(从上往下查找,谁先出现谁先加载)
问题三,Jar包冲突(无法掉的)
HBaseReader插件引入的hbase-client依赖中自带引入了低版本的Guava包(12.0.1),但是项目中MySQLReader里用到了高版本的Guava包(28.1),两个版本的Guava包都包含各自独有的方法,去掉其中一边都会导致另一边报错。
解决方案:
1.依赖覆盖:找到能与项目各模块兼容的Guava包,并利用Maven依赖加载的优先级关系对包覆盖
2.使用maven-shade-plugin插件来对overwatch 依赖的Jar包重命名
3.直接搜索有无现成可用的shaded包,shaded包把所有的东西都打包编译了,不会造成Jar包冲突。本次因为高版本Guava包和hbase-client的不兼容问题,也使用hbase-shaded-client成功解决
总结
先用Maven Helper插件将冲突的Jar包剔除,若还是报错,则说明需要不同版本的同名Jar包。
此时需要将Jar包利用maven-shade-plugin插件打包,或者在Maven仓库中直接寻找shaded版本的Jar包。