Java中的NoClassDefFoundError报错含义解析
作者:用户bPbhIAe
引言
半夜睡得正香的时候,突然接到警告电话,于是翻起身就打卡电脑连上环境查看是什么情况?登录上之后发现有个微服务占用的句柄数量一直在持续上涨,最终导致了微服务内存溢出挂掉了。这个微服务在运行的过程中会建立SSH
连接,且之前这个微服务已经遇到过很多次类似的情况了,因此第一反应是哪里建立的连接又没有关闭。
猜肯定是猜不出来的,所以第一步肯定先看下日志里面哪里在报错,然后才好对症下药。打开日志之后,经过一番排查,发现日志里面有个很奇怪的报错,日志里面有打印NoClassDefFoundError
。最开始的我对这个错误的理解是不够深刻的,我的第一反应是Class
文件找不到了。于是我切换到微服务的路径下,去找这个Class
文件,发现文件是存在的。于是我又想,难道是文件的权限不对?我又用了ll
命令看了一下文件的权限,发现文件的权限也是对的。这个时候我有点懵了,心想完了,这道题不会呀,老师没教过呀!
没办法,为了保住工作,硬着头皮还是得上。俗话说,源码之下无秘密,只有根据堆栈找到对应的源代码进行分析,看看有什么怀疑点,然后又从网上搜索了一下NoClassDefFoundError
报错的含义。经过我的深思熟虑终于发现了问题的所在。
NoClassDefFoundError的报错含义
首先需要了解一下NoClassDefFoundError
的报错含义,参考why-am-i-getting-a-noclassdeffounderror-in-java这个帖子:
这段话说:NoClassDefFoundError这个报错说明之前JVM尝试过去加载这个类,但是因为某些原因失败了。现在又要使用到这个类,所以又会触发这个类的加载,但是因为之前加载这个类失败了,所以这次就不会去加载这个类了,而是直接抛出NoClassDefFoundError这个报错。
解析
如果上面这段话不好理解,可以看下面这个例子,这个例子也是来自于上面那个帖子中的回答:
public class NoClassDefFoundError { public static void main(String[] args) { try { // 这里尝试new一个对象,会触发SimpleCalculator的第一次加载 SimpleCalculator calculator1 = new SimpleCalculator(); } catch (Throwable t) { System.out.println(t); } // 这里又尝试new一个对象,会触发SimpleCalculator的第二次加载 SimpleCalculator calculator2 = new SimpleCalculator(); } } class SimpleCalculator { // 类加载的时候会初始化这个类变量,这里会抛出一个运行时异常 static int undefined = 1 / 0; }
从上面的运行结果可以看到,在代码的第12行抛出了NoClassDefFoundError
的报错,这里也是第二次尝试加载这个类的地方。第一次尝试初始化SimpleCalculator
这个类时,因为初始化会初始化 undefined
这个变量,而这个变量在初始化过程中会抛出一个异常,满足了第一次报错的条件,然后第12行尝试第二次初始化这个类,因为第一次已经初始化失败了,这个时候 JVM 就直接抛出NoClassDefFoundError
这个报错,而不是尝试再次去加载这个类。
当然实际的代码不可能会写出这么明显的Bug,我出问题的代码大概是长如下这样:
public class XXXUtils { private static final XXXBean bean = SpringContextUtils.getBean(XXXBean.class); } public class SpringContextUtils { public static <T> T getBean(Class<T> clazz) { return context.getBean(clazz); } } public class XXXClazz { public static void xxxMethod() { XXXUtils.xxxMethod(); } } public class Session { try { XXX conn = xxx; } finnaly { XXXUtils.closeConn(conn); } }
其中的工具类 XXXUtils
实际依赖了 SpringContexUtils
来获取 Bean
,也就是依赖 Spring
上下文初始化好。但是实际在服务启动的过程中又触发了 XXXClass
的 xxxMethod
调用了 XXXUtils
的方法,这个时候就会触发 XXXUtils
的类加载,也就会触发它的 bean
变量的初始化,但是由于这个时候 Spring
上下文还没有初始化好,因此调用 SpringContextUtils.getBean()
方法就会抛出异常。在第一次初始化 XXXUtils
失败之后,等到服务正常启动,其它地方再调用 XXXUtils
的方法时,就会抛出 NoClassDefFoundError
错误,导致了 XXXUtils
的所有方法都不可用,而正常的SSH连接结束之后,会调用 XXXUtils.closeConn()
方法关闭连接,当然,因为这个时候方法不可用,所以连接也关不掉,最终导致了的句柄数量不断上涨,服务也挂掉了。
以上就是Java中的NoClassDefFoundError报错解析的详细内容,更多关于Java中的NoClassDefFoundError报错解析的资料请关注脚本之家其它相关文章!
您可能感兴趣的文章:
- 解决java.lang.NoClassDefFoundError:lombok/Data报错问题
- 解决java.lang.NoClassDefFoundError错误的问题
- java.lang.NoClassDefFoundError错误的原因及解决方法
- maven引入本地jar包运行报错java.lang.NoClassDefFoundError解决
- Java中NoClassDefFoundError 和 ClassNotFoundException的区别
- 解决java.lang.NoClassDefFoundError: android.support.v4.animation.AnimatorCompatHelper问题
- Java之NoClassDefFoundError的原因及分析