Maven项目引入scala-redis后初始化SparkSession出现NoClassDefFoundError如何解决
报错产生原因
- 最直接的原因是运行时类路径缺失Spark SQL相关依赖:抛出的
java.lang.ClassNotFoundException: org.apache.spark.sql.SparkSession$明确说明JVM加载类时找不到SparkSession的核心类,通常是Maven未引入Spark SQL依赖,或是依赖的scope被设置为provided、本地运行环境未提供对应Spark依赖包导致。 - 其次代码存在初始化顺序逻辑错误:你在实例化RedisClient之前就调用了
getAppName方法(SparkSession初始化时会先执行入参里的getAppName,此时val r = new RedisClient(...)还未执行),即使解决了类找不到的问题,后续也会因为RedisClient未初始化抛出空指针异常。 - 此外如果项目Scala主版本和依赖的Scala版本不匹配,也可能触发类加载异常,比如你用的
scala-redis_2.11要求项目Scala版本必须为2.11.x,和Spark依赖的Scala版本也需保持一致。
修复方案
- 补全Spark SQL依赖,根据你的项目Scala版本和Spark版本选择对应依赖,本地调试阶段不要设置
scope为provided,示例依赖(适配Scala 2.11 + Spark 2.4.x版本):
<!-- Spark SQL 依赖 --> <dependency> <groupId>org.apache.spark</groupId> <artifactId>spark-sql_2.11</artifactId> <version>2.4.8</version> </dependency> <!-- Spark Hive 依赖(你用了enableHiveSupport需要加这个) --> <dependency> <groupId>org.apache.spark</groupId> <artifactId>spark-hive_2.11</artifactId> <version>2.4.8</version> </dependency>
如果是要提交到Spark集群运行,打包时可以把这两个依赖的scope设为provided,用集群自带的Spark依赖减少包体积。
- 调整代码初始化顺序,把RedisClient的实例化移到SparkSession初始化之前,同时增加Redis返回值判空逻辑避免空指针,调整后的代码示例:
// 先实例化RedisClient val r = new RedisClient("localhost", 6379) def getAppName:String={ val a = r.get("xyz") a match { case Some(v) => logger.info("******** xyz ************"+ v) v case None => logger.warn("未从Redis读取到xyz配置,使用默认应用名") "default_app_name" } } // 再初始化SparkSession val sparkSession=SparkSession.builder.appName(getAppName).enableHiveSupport().getOrCreate()
- 统一项目的Scala版本为2.11.x,保证所有带Scala版本后缀的依赖(_2.11)和项目Scala版本一致,避免版本冲突。
内容的提问来源于stack exchange,提问作者Abhishek
相关产品推荐
相关产品推荐

