Jar包冲突解决方案

背景介绍

项目名称:数据同步中心的HBaseReader插件迁移至玄武计算平台

项目背景:数据同步中心的开发环境为Spark 2.x + Scala 2.11,而玄武计算平台中的开发环境为Spark 3.0 + Scala 2.12,且开发环境所用HBase版本较低,所以在迁移中遇到了许多API错误和Jar包冲突问题

问题一,Spark版本升级导致以前的API调用方式不可用

旧版本调用在新版本中报错,如下图所示:
Jar包冲突解决方案
点进去查看该类发现在Spark 3.0 中该对象被私有化,无法调用

Jar包冲突解决方案Jar包冲突解决方案

解决方案:本地构建一个DYSparkHadoopUtil,将用到的SparkHadoopUtil代码拷贝进去,并把调用的对象设为公有类型,在项目中import DYSparkHadoopUtil即可

Jar包冲突解决方案Jar包冲突解决方案

问题二,Jar包冲突(可以掉的)

Jar包冲突产生的报错信息:NoClassDefFoundError、NoSuchMethodError、ClassNotFoundException

问题本质是由于JVM在加载Class文件的时候,加载了不一致的Class。可以手工剔除掉有问题的Maven依赖,但是当项目依赖较多时,人工寻找冲突的Jar包或者使用Maven自带的show dependencies会非常卡顿

解决方案:使用Maven Helper插件剔除(快速方便)

在Maven环境下Jar的加载顺序跟依赖树的节点位置相关,我们可以使用 mvn dependency:tree 来打印,或者在IDEA中安装 MavenHelper 插件来查看工程的依赖树,如下图:
Jar包冲突解决方案

定位到具体的冲突包后,利用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成功解决

Jar包冲突解决方案

总结

先用Maven Helper插件将冲突的Jar包剔除,若还是报错,则说明需要不同版本的同名Jar包。

此时需要将Jar包利用maven-shade-plugin插件打包,或者在Maven仓库中直接寻找shaded版本的Jar包。