一次非常误导人的NoClassDefFoundError
摘要
NoClassDefFoundError有时候未必如类名所示那样,运行时找不到某一个类。而可能会是某种八竿子打不着的奇葩原因所致:比如栈溢出StackOverFlow。
踩坑经历
接手一个老项目,碰到了一个离奇的问题:在使用Jenkins构建测试环境启动时经常会抛出一个奇怪的异常:
java.lang.NoClassDefFoundError: org.springframework.beans.FatalBeanException
详细截图:
由于本机启动正常,首先怀疑的是测试环境jar包冲突、或者jar包版本不对,以至于运行时没有加载到FatalBeanException这个类。
然而排查了许久,并使用了jvm参数-verbose来打印出所有类加载的信息,发现jar包并没有问题,FatalBeanException这个类也是正常加载进了jvm之中。所以,并不是jar包的问题。
我和我的小伙伴们的思路顿时走进了死胡同,百思不得其解。最终只好从源码入手,在抛出异常的地方打断点调试:
首先是最外层的异常:
点开ex一看堆栈是这样的:
org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:334)
定位到AutowiredAnnotationBeanPostProcessor.java:334打断点重新启动,发现是在此catch住了一个异常,并throw了一个BeanCreationException
点开此处catch的异常,长这样:
继续追溯至org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredMethodElement.inject(AutowiredAnnotationBeanPostProcessor.java:661)
断点重启:
原来是个stackOverFlowError,真是fuck了。原因是这个项目太臃肿了,spring在启动时候加载大量的依赖,导致方法调用链过高,最终导致了栈溢出。
于是增大栈内存:-Xms1m,重启,问题解决。
结论
有时候,系统给的异常信息是会误导人的。此时就需要我们动用聪明的大脑,从源码入手,来找出问题的真正原因。