Spring与Spark依赖冲突排查:Scala序列化类转换异常求助
解决Spring Boot + Spark MLlib的ClassCastException依赖冲突问题
这个java.lang.ClassCastException(Scala集合序列化代理类无法赋值)的问题我在Spring Boot整合Spark的项目里碰过好几次,核心就是Spring Boot的依赖管理和Spark的Scala版本依赖打架了,尤其是Scala集合类的序列化逻辑不一致导致的。咱们一步步来修复:
问题根源拆解
- Spark 2.4.x是基于Scala 2.11构建的,它依赖的Scala集合类版本,和Spring Boot打包时可能引入的重复Scala类(或者依赖传递来的不同版本)不兼容
spring-boot-maven-plugin的repackage机制在打包时,会把所有依赖的类合并到最终Jar里,这就把冲突的Scala类也混进去了,Spark运行时加载了错误版本的类,自然就抛出转换异常
具体修复方案
1. 显式锁定Spark Core版本并排除冲突日志依赖
Spark MLlib依赖Spark Core,但只引入spark-mllib_2.11的话,容易出现依赖传递带来的版本不一致。直接显式添加spark-core_2.11,版本和MLlib保持一致(2.4.3),同时排除和Spring Boot日志框架冲突的依赖:
<dependency> <groupId>org.apache.spark</groupId> <artifactId>spark-core_2.11</artifactId> <version>2.4.3</version> <exclusions> <exclusion> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> </exclusion> <exclusion> <groupId>log4j</groupId> <artifactId>log4j</artifactId> </exclusion> </exclusions> </dependency>
2. 隔离Spring Data Cassandra与Spark Cassandra Connector的冲突
spring-boot-starter-data-cassandra会引入自己的Cassandra驱动,这和你用的spark-cassandra-connector-unshaded_2.11会有依赖冲突,得把它排除掉:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-cassandra</artifactId> <version>2.0.9.RELEASE</version> <exclusions> <exclusion> <groupId>com.datastax.cassandra</groupId> <artifactId>cassandra-driver-core</artifactId> </exclusion> <exclusion> <groupId>com.datastax.cassandra</groupId> <artifactId>cassandra-driver-mapping</artifactId> </exclusion> </exclusions> </dependency>
3. 调整Spring Boot打包插件配置
你的spring-boot-maven-plugin已经加了requiresUnpack,但还要把Spark MLlib也加进去,另外排除Scala核心依赖,让Spark集群来提供这些类,避免打包时把冲突的Scala类带进去:
<plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <version>2.0.9.RELEASE</version> <executions> <execution> <goals> <goal>repackage</goal> </goals> </execution> </executions> <configuration> <requiresUnpack> <dependency> <groupId>org.apache.spark</groupId> <artifactId>spark-core_2.11</artifactId> </dependency> <dependency> <groupId>org.apache.spark</groupId> <artifactId>spark-streaming_2.11</artifactId> </dependency> <dependency> <groupId>org.apache.spark</groupId> <artifactId>spark-mllib_2.11</artifactId> </dependency> </requiresUnpack> <!-- 让Spark集群提供Scala核心类,避免打包冲突 --> <excludeGroupIds>org.scala-lang</excludeGroupIds> </configuration> </plugin>
4. 用BOM锁定Jackson版本(可选但推荐)
虽然你已经指定了Jackson的版本,但用BOM可以确保所有Jackson相关依赖版本完全一致,避免传递依赖带来的版本差异:
<dependencyManagement> <dependencies> <dependency> <groupId>com.fasterxml.jackson</groupId> <artifactId>jackson-bom</artifactId> <version>2.9.8</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>
验证步骤
- 先执行
mvn clean package重新打包,确保没有依赖冲突的警告 - 启动应用后,再测试PCA、聚类、相关性计算这些操作
- 如果还有问题,运行
mvn dependency:tree查看依赖树,搜索scala-lang相关的依赖,看看有没有其他未排除的冲突版本
内容的提问来源于stack exchange,提问作者ktzan
相关产品推荐
相关产品推荐

