http://www.paraller.com/2018/12/12/NoClassDefFoundError-&-ClassNotFoundException%E6%80%BB%E7%BB%93/
最近一个应用程序A,引入了一个二方包 xxx-common.jar, 能够正常运行。 然后应用B也引用了这个二方包,部署启动也都正常,但是使用 xxx-common.jar 的一个类的静态方法时,却抛出了一个异常 NoClassDefFoundError
。
借这个排查的机会把这个异常重新学习了一下,首先是理解两种异常的区别,因为长得很像,大家很容易混在一起。
首先理解两种异常的区别:
ClassNotFoundException :
受检异常,在应用启动的时候,加载不到相应的类就会抛出异常,常见场景:
- 1、没有引入相应的jar包。
- 2、包冲突,不同的jar包中有相同的类
一般在编译的时候就会报异常,或者在调用反射代码的时候报异常 ,所以我们在启动spring容器的时候偶尔会看到这种异常。
Class.forName("").newInstance()
// Class.forName() 、 ClassLoader.loadClass() 、 ClassLoader.findSystemClass()
NoClassDefFoundError
NoClassDefFoundError 是fata error,主线程发生异常时整个程序都会挂掉, 当JVM初始化一个对象 或者 调用类的静态方法 ,不能找到class文件的时候就会报这个错。
出现异常一般是因为这几种原因:
- 1、编译时和运行时的classpath不一致,导致无法加载到类。
- 2、引入的jar包的JDK版本和应用支持的JDK版本不一致,也会导致无法加载类。
- 3、执行对象的静态代码块或者初始化静态域的时候抛异常,导致类无法成功初始化。
1、2 好理解,主要梳理一下第三种情况
这种错误一般在编译期是不会出现的,在运行时加载类的时候才会出现,通常在执行静态代码块或者初始化类中的静态域的时候抛出异常,就会导致类初始化失败。
复现错误:
public class NoClassDefTest {
public static void main(String[] args) {
NoClassDefFoundErrorExample noClassDefFoundErrorExample = new NoClassDefFoundErrorExample();
noClassDefFoundErrorExample.getClassWithInitErrors();
}
}
class ClassWithInitErrors {
// 静态域抛出异常,导致无法初始化类
static int data = 1 / 0;
}
class NoClassDefFoundErrorExample {
public ClassWithInitErrors getClassWithInitErrors() {
ClassWithInitErrors test;
try {
test = new ClassWithInitErrors();
} catch (Throwable t) {
System.out.println("Throwable--->" + t);
}
test = new ClassWithInitErrors();
return test;
}
}
Throwable--->java.lang.ExceptionInInitializerError
Exception in thread "main" java.lang.NoClassDefFoundError: Could not initialize class ClassWithInitErrors
at NoClassDefFoundErrorExample.getClassWithInitErrors(NoClassDefTest.java:38)
at NoClassDefTest.main(NoClassDefTest.java:21)
解决方案:
-
确认你需要的类在classpath中,查看你的 IDE :maven - external Libraries即可
-
确保classpath没有被覆盖(被脚本所修改),在运行的程序中,加上代码
System.getProperty("java.class.path")
打印你加载的jar包。 -
运行时明确指定你认为程序能正常运行的 -classpath 参数,如果增加之后程序能正常运行,说明原来程序的classpath被其他人覆盖了。
-
如果你的应用使用了多个类加载器,类A被加载器X加载了,那么对于加载器Y就不可用了。
-
确认应用所支持的JDK版本,以及引用的二方包版本信息。
总结:
异:NoClassDefFoundError编译期存在类,运行时在classpath中无法找到。
同:两种异常都和 classpath 以及 运行时无法找到class相关。
参考网站
怎么解决java.lang.NoClassDefFoundError错误 ClassNotFoundException vs NoClassDefFoundError