使用Maven Shade Plugin的Apache Spark项目Jackson Databind冲突问题
解决Spark项目中Jackson版本冲突问题
核心原因
你的问题本质是EMR集群自带的旧版Jackson(2.12.7-1)优先级高于你胖JAR中的2.15.2版本。Spark的类加载机制会优先加载集群环境中的系统依赖,而非用户JAR里的依赖,导致版本不匹配触发Scala模块的版本校验错误。
解决方案
1. 使用Maven Shade插件重命名Jackson包(最推荐)
通过Shade的Relocator把Jackson的包路径重命名,彻底隔离用户依赖和集群依赖,从根源避免类冲突。修改你的maven-shade-plugin配置:
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-shade-plugin</artifactId> <version>3.2.4</version> <executions> <execution> <phase>package</phase> <goals> <goal>shade</goal> </goals> <configuration> <relocations> <!-- 重命名Jackson所有核心包路径 --> <relocation> <pattern>com.fasterxml.jackson</pattern> <shadedPattern>shaded.com.fasterxml.jackson</shadedPattern> </relocation> </relocations> <transformers> <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"> <mainClass>org.example.Main</mainClass> </transformer> </transformers> <filters> <filter> <artifact>*:*</artifact> <excludes> <exclude>META-INF/*.SF</exclude> <exclude>META-INF/*.DSA</exclude> <exclude>META-INF/*.RSA</exclude> </excludes> </filter> </filters> </configuration> </execution> </executions> </plugin>
重命名后,你的代码会使用shaded.com.fasterxml.jackson下的类,完全避开集群的旧版Jackson。
2. 强制Spark优先加载用户JAR依赖
提交Spark应用时,添加类加载优先级参数,让用户JAR的依赖先于集群依赖加载:
spark-submit \ --class org.example.Main \ --conf spark.driver.userClassPathFirst=true \ --conf spark.executor.userClassPathFirst=true \ your-fat-jar.jar
注意:这个参数可能引发其他依赖冲突(比如Spark自身依赖版本不兼容),需要测试验证。
3. 完善Spark依赖的Jackson排除
确保所有Spark相关依赖都彻底排除旧版Jackson,在你的pom.xml中修改Spark依赖:
<!-- Spark Core --> <dependency> <groupId>org.apache.spark</groupId> <artifactId>spark-core_2.13</artifactId> <version>3.5.1</version> <exclusions> <exclusion> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> </exclusion> <exclusion> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-core</artifactId> </exclusion> <exclusion> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-annotations</artifactId> </exclusion> <exclusion> <groupId>com.fasterxml.jackson.module</groupId> <artifactId>jackson-module-scala_2.13</artifactId> </exclusion> </exclusions> </dependency> <!-- Spark SQL --> <dependency> <groupId>org.apache.spark</groupId> <artifactId>spark-sql_2.13</artifactId> <version>3.5.1</version> <exclusions> <exclusion> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> </exclusion> <exclusion> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-core</artifactId> </exclusion> <exclusion> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-annotations</artifactId> </exclusion> <exclusion> <groupId>com.fasterxml.jackson.module</groupId> <artifactId>jackson-module-scala_2.13</artifactId> </exclusion> </exclusions> </dependency>
这样可以确保项目不会引入Spark传递的旧版Jackson。
4. EMR集群层面调整(可选)
如果上述方法仍无效,可以通过EMR Bootstrap动作修改集群的Spark依赖:
- 在集群启动时,替换
/usr/lib/spark/jars下的旧版Jackson JAR为你需要的2.15.2版本 - 或者在
spark-defaults.conf中添加spark.driver.extraClassPath和spark.executor.extraClassPath,指定你的Jackson JAR路径
验证方法
打包后,使用jar tf your-fat-jar.jar查看是否存在shaded/com/fasterxml/jackson路径下的类;运行应用时,添加日志参数-Dorg.slf4j.simpleLogger.defaultLogLevel=debug,查看类加载路径,确认加载的是你打包的Jackson版本。
内容的提问来源于stack exchange,提问作者prashantjerk
相关产品推荐
相关产品推荐

