排查这个问题时,maven项目不止这一个报错,对于问题排查制造了很多麻烦。
下面介绍的是NoClassDefFoundError排查通用的排查方法,其中以java.lang.NoClassDefFoundError:org/slf4j/LoggerFactory为例进行排查分析。
NoClassDefFoundError这个报错表示class找不到,可能的原因有三种:
1. 依赖的Jar没引入maven
2. Jar包冲突
3. 打包build问题。
先定位是IDE中运行报错还是打包之后的运行报错,如果是后者,那就不用排查1和2了,直接按照3排查。
假设是IDE运行时报错,于是一次排查1和2。
1. 依赖是否已引入的排查
两种办法:
a.检查所在module的pom.xml及工程的总pom.xml文件中是否已经添加了相关配置;
b. 通过IDE确认。
第二种更直观。如下图intelliJ idea,点击IDE右侧的maven Project,可以查看报错的module下面的dependecies,看是否有依赖的包。
还可以选中module名称,点击右上角的拓扑图icon生成如左侧的Jar包依赖关系图。mac下command+F,打开Diagram Elements窗口,直接敲入需要查找的Jar包名称即可联想搜索出jar包名,点击jar包名称即可在Jar包依赖关系图中定位到具体的Jar包。
一般排查是否存在直接看右侧的dependencies就可以了,如果不存在,就需要在module或工程的pom.xml文件中添加依赖。
经确认,org/slf4j/LoggerFactory需要的slf4j-api.jar和slf4j-log4j12.jar和log4j.jar 都已引入。
2. Jar包冲突排查
这种情况大多是由于pom配置引入了多个版本的Jar包,或者有相互依赖关系的Jar包之间版本不一致,导致在运行的过程中找错了版本,或版本错误找不到对应的class方法。
a. 定位依赖的Jar包
找到报错点,进入目标类.以intelliJ idea为例,点击左侧project工具栏的定位icon,就会展开External Libraries并定位到目标Jar包。
private final static Logger logger = LoggerFactory.getLogger(MainEntry.class);
b. 确认依赖的Jar包工程里是否只有一个版本
在展开的External Libraries中即可确认。如果存在多个版本,就要梳理pom文件看是否给了多个version版本号,例如工程pom里一个version,module的pom里一个version。此时需要根据需要只保留一个version。
也可能是有其它的Jar包X的子包中同样引入了这个Jar包,导致存在多个。如果这个其它Jar包X中引入的是多余的,就需要在这个其它Jar包X的pom文件dependencies配置处加exclusions排除掉这个子包。
c. 多个关联Jar包版本冲突
这时候需要访问https://mvnrepository.com/ 搜索到目标Jar包,然后向下翻,找到它依赖的Jar包及其version。然后在工程的pom引入中保证关联的Jar包之间版本号一致。
经排查,项目中用到的org/slf4j/LoggerFactory关联的这三个Jar包引入的版本号满足需要,不存在冲突问题。
3. 打包build问题排查
这种最直接的表现就是IDE中运行ok,但是打包之后运行就会报错。于是排查重点就在pom文件中的build配置上。发现在build的原配置中做了excludes,其中把org.slf4j*和log4j*都排除掉了,因此打包的时候就不会把相关的class打进去,造成了NoClassDefFoundError。去掉这个exclude就好了。
应该是之前项目框架中是包含log相关的依赖的,因此不需要额外打包进去,这样可以为Jar包瘦身,后来框架变化了,没有这部分依赖了,就需要再添加回来。
还有另外一个博主遇到的情况是JRE里边他自己放了一个依赖Jar包,maven又引入了一个,也造成了版本冲突。删除JRE里边的就好了。
org.apache.maven.plugins
maven-compiler-plugin
org.apache.maven.plugins
maven-shade-plugin
package
shade
org.apache.flink:force-shading
com.google.code.findbugs:jsr305