如何在Spark应用运行时强制lib_A使用指定版本的commons-io?
搞定HDInsight Spark里commons-io版本冲突的坑
为啥会出这问题?
HDInsight 5.0自带的commons-io 2.5.0是在系统类加载器里的,Spark默认用父类优先的类加载策略——也就是先找系统里的旧版本,你自己打包的2.11.0版本在应用类加载器里根本轮不上被加载,自然找不到新增的consume()方法。
怎么解决?
1. 确保2.11.0被正确打进应用包
之前你排除lib_A依赖再手动加新版本的思路是对的,但得确保Gradle把这个jar确实打包进去。调整你的Gradle配置:
// 先把lib_A里自带的commons-io排除掉 implementation ('com.example:lib_A:x.x.x') { exclude group: 'commons-io', module: 'commons-io' } // 显式引入2.11.0,用implementation确保它被打包到fat jar里 implementation 'commons-io:commons-io:2.11.0'
然后用Shadow插件或者Spark Assembly插件打fat jar,别漏了这个jar。
2. 强制Spark优先加载应用里的类
提交应用的时候加两个配置,让应用类加载器先干活,别先找系统里的旧jar:
spark-submit \ --class com.your.package.YourMainClass \ --conf spark.driver.userClassPathFirst=true \ --conf spark.executor.userClassPathFirst=true \ 你的应用fat.jar
⚠️ 注意:这个参数可能会搞乱其他依赖的加载顺序(比如Spark自带的一些jar),所以打完包一定要测试全流程。
3. 实在不行就指定额外类路径
如果上面的配置不管用,直接把commons-io 2.11.0的jar传给Spark,让它优先加载:
spark-submit \ --class com.your.package.YourMainClass \ --jars commons-io-2.11.0.jar \ --conf spark.driver.userClassPathFirst=true \ --conf spark.executor.userClassPathFirst=true \ 你的应用.jar
这样Spark会把这个jar加到类路径最前面,优先加载。
4. 验证下是不是真的生效了
加几行代码打印当前加载的版本,省得白忙活:
import org.apache.commons.io.IOUtils; // 在main方法里调用这个方法 public static void checkCommonsIoVersion() { String version = IOUtils.class.getPackage().getImplementationVersion(); System.out.println("当前加载的commons-io版本:" + version); }
跑起来看日志,要是显示2.11.0就搞定了。
内容的提问来源于stack exchange,提问作者coders
相关产品推荐
相关产品推荐

