Java单元测试可导入Spark类却无法引用?functions报NoClassDefFoundError求助
functions类报NoClassDefFoundError的思路 这种问题我之前做Spark单元测试时也碰到过,大概率是依赖配置或者类路径的问题,咱们一步步来排查:
检查Spark SQL依赖的Scope配置
很多同学会把Spark相关依赖的scope设为provided,这个配置是告诉构建工具“运行时由容器(比如YARN、Spark集群)提供这个依赖”,但单元测试是在本地环境运行,没有集群容器提供依赖,自然就找不到functions类了。
如果是Maven项目,你可以修改依赖配置:<!-- 原来的可能是这样,测试时无法获取到依赖 --> <dependency> <groupId>org.apache.spark</groupId> <artifactId>spark-sql_2.12</artifactId> <version>3.3.0</version> <scope>provided</scope> </dependency> <!-- 改成测试可用的配置,要么去掉scope(默认compile,测试和主代码都能用),要么单独加test scope的依赖 --> <dependency> <groupId>org.apache.spark</groupId> <artifactId>spark-sql_2.12</artifactId> <version>3.3.0</version> <scope>test</scope> </dependency>Gradle项目的话,对应调整
compileOnly为testImplementation即可。确认测试类路径包含Spark SQL依赖
用IDE的话,比如IDEA,打开File -> Project Structure -> Modules -> Dependencies,查看Spark SQL的依赖是否被标记为Test范围(或者同时包含主代码和测试代码的范围)。
也可以用构建工具命令检查类路径:Maven执行mvn dependency:build-classpath -Dmdep.outputFile=classpath.txt,打开生成的classpath.txt,确认里面有Spark SQL的jar包,并且这个jar包中确实包含org.apache.spark.sql.functions类(可以解压jar包查看)。排查依赖冲突
可能存在不同版本的Spark SQL依赖导致类加载冲突,比如某个第三方依赖引入了旧版本的Spark SQL,覆盖了你的目标版本。
用Maven命令mvn dependency:tree查看依赖树,搜索spark-sql,如果发现多个版本,就排除掉不需要的那个。比如:<dependency> <groupId>com.example</groupId> <artifactId>some-third-lib</artifactId> <version>1.0.0</version> <exclusions> <exclusion> <groupId>org.apache.spark</groupId> <artifactId>spark-sql_2.12</artifactId> </exclusion> </exclusions> </dependency>清理缓存并重新构建
有时候IDE或构建工具的缓存会导致奇怪的类加载问题,先执行构建工具的清理命令:Maven用mvn clean,Gradle用gradle clean,然后重新执行mvn test-compile(或Gradle的gradle testClasses)。
另外,IDEA可以尝试File -> Invalidate Caches...,选择清除缓存并重启IDE,很多这类疑难问题都能通过这个操作解决。最后确认导入拼写
你代码里的import org.apache.spark.sql.functions;是正确的,不过再仔细检查下有没有拼写错误(比如少写了s),毕竟有时候手滑也会出问题。
一般来说,调整依赖的scope是解决这个问题最常见的办法,先从这个方向入手排查应该就能解决。
内容的提问来源于stack exchange,提问作者Zhe Hou

