Bazel运行Spark对接Kafka代码构建成功报org.json4s.JsonAST$JValue类找不到错误
问题描述
我正在开展Kafka相关的POC验证,需要将数据集写入Kafka Topic并从中读取数据,计划创建如下Struct类型应用于从Kafka Topic读取的数据,代码如下:
import org.apache.spark.sql.DataFrame import org.apache.spark.sql.types.{MapType, StringType, StructField, StructType} import org.apache.spark.sql.functions._ val df = spark .read .format("kafka") .options(Admin.commonOptions) .option("subscribe", topic) .load() df.printSchema() val personStringDF = df.selectExpr("CAST(value AS STRING)") println("personStringDF--") personStringDF.show() personStringDF.printSchema() val schemaTopic: StructType = StructType( Array( StructField(name = "col1", dataType = StringType, nullable = false), StructField(name = "col2", dataType = StringType, nullable = false) ))
BUILD文件配置如下:
java_library( name = "spark", exports = [ "@maven//:org_apache_spark_spark_core_2_12", "@maven//:org_apache_spark_spark_sql_2_12", "@maven//:org_apache_spark_spark_unsafe_2_12", "@maven//:org_apache_spark_spark_tags_2_12", "@maven//:org_apache_spark_spark_catalyst_2_12", "@maven//:com_fasterxml_jackson_core_jackson_annotations", "@maven//:com_fasterxml_jackson_core_jackson_core", "@maven//:com_fasterxml_jackson_core_jackson_databind", "@maven//:com_typesafe_play_play_json_2_12_2_9_1", "@maven//:org_json4s_json4s_ast_2_12_4_0_0", "@maven//:org_json4s_json4s_jackson_2_12_4_0_0" ], )
运行代码时报错:Exception in thread "main" java.lang.NoClassDefFoundError: org/json4s/JsonAST$JValue
通过Bazel运行该代码,workspace文件中已经引入了所有相关依赖,Bazel构建过程完全正常,仅在运行时出现该错误。
错误触发原因
- 依赖版本冲突:你手动引入的json4s 4.0.0版本和当前使用的Spark版本内置的json4s版本不兼容。Spark内置的json4s版本通常为3.6.x/3.7.x,不同版本的JsonAST类结构有差异,运行时类加载器优先加载了版本不匹配的类,导致找不到对应子类。
- Bazel运行时依赖缺失:Bazel构建期仅校验编译需要的类是否存在,不会校验运行时的全量类路径。如果你的运行目标(比如java_binary)没有正确传递该spark库的所有依赖,或者运行时没有把json4s依赖加载到classpath中,也会触发该错误。
- Spark提交场景的类加载优先级问题:如果是通过spark-submit提交任务,Spark默认会优先加载自身安装包内置的依赖,你打包在应用中的json4s会被忽略,版本不匹配就会触发类找不到错误。
解决方案
- 版本对齐:先查询你当前使用的Spark版本对应的官方依赖树,将引入的json4s版本替换为Spark内置的对应版本,消除版本差异。
- 排除冲突依赖:如果是通过spark-submit提交任务,在BUILD的依赖配置中排除json4s相关的手动引入,直接使用Spark运行环境自带的json4s依赖即可。
- 修正Bazel运行配置:如果是本地直接用Bazel run运行,确保你的java_binary运行目标正确依赖了上述spark库,若需要打可执行的fat包,使用
bazel build :xxx_deploy.jar生成包含所有依赖的部署包再运行。 - 临时调整类加载优先级:如果需要强制使用自定义的json4s版本,spark-submit时添加如下参数:
--conf spark.driver.userClassPathFirst=true --conf spark.executor.userClassPathFirst=true,该方案可能引发其他依赖冲突,仅建议临时验证使用。
内容的提问来源于stack exchange,提问作者AKene
相关产品推荐
相关产品推荐

