场景描述
最近上线了一个项目,本地 编译+运行 都是没有任何错误或者异常,但是 一旦部署到线上 ,就会出现NoClassDefDoundError 错误
错误模拟
java.lang.NoClassDefDoundError:xxx/xxx/xxx/xxx/类A
问题分析
注意:该场景分析指针对静态方法而言。
我们都知道 NoClassDefDoundError:xxx 错误的出现 ,本质上是jvm在运行时,找不到相应的类。
那这个类为什么不在编译的时候不会报出来呢?之所以没报出来,是和类的加载机制有关系。
一般情况下,当我们调用一个静态方法时,jvm根据ClanderUrl,只会校验 该静态方法所在的这个类是否存在,而不会再去校验该类中所依赖的其它类是否存在,这才导致 在编译时期检查不出该问题。
第一次尝试解决
我们经过刚才的那波分析,大致已经了解了问题的本质 ,便根据 场景描述中
java.lang.NoClassDefDoundError:xxx/xxx/xxx/xxx/类A
去查找编译好的A类class文件是否存在 ,发现存在(事实还原),感觉应该没问题了吧,部署到线上,运行。
悲剧重现
部署完成后 ,进行测试 ,然后 发现 ,卧槽!!! 居然 没解决 !
连续测试 ,查看日志,可结果依然是
java.lang.NoClassDefDoundError:xxx/xxx/xxx/xxx/类A
再次分析
此时,心里很郁闷,自己明明检测过了,没问题 为什么还会出现这个问题 ,于是 循环上一步 ,检查编译产物,发现还是没问题,继续部署 。
由于上次部署的教训,这次部署时,严谨对待每一步,时时刻刻盯着日志。
功夫不负有心人,终于发现了不一样 !!!就是 ,在第一次调用的时候,报错信息出现了不同
。出现了
java.lang.NoClassDefDoundError:xxx/xxx/xxx/xxx/类B
.....中间省略其它报错信息....
java.lang.NoClassDefDoundError:xxx/xxx/xxx/xxx/类A
此时 ,看到了一个不一样的类,类B !
多次点击测试,发现 只有第一次测试时,才会出现类B的错误提示。于是 猜测是不是 类B的class文件不存在,于是 抱着侥幸的心理去查找类B的 class文件,结果发现 还真没有。
又于是 ,引入类B所在的依赖 ,然后部署。最后结果 居然运行成功了。问题到此解决
问题总结
至于问题发生的原因 在第一次分析的时候 ,已经分析过了,是jvm在运行时 无法找到该类。所以只要引入对应的依赖即可,尤其注意二方包依赖的引用。
关于错误日志 ,该错误日志 ,一定要留意第一次调用时给出的异常信息,关键点很有可能在这里。