NoClassDefFoundError/ClassNotFoundException 到底从哪引用到了这个类?排查思路


1、背景

公司内网登录改造升级,使用方需要配合升级 jar 包。

本以为很简单的事情,升级版本上线就 OK 了。没想到升级头一个服务,部署到测试环境就有问题。

2、表象

访问所有页面报 404。

3、排查思路

3.1 排除法,确定是不是升级 jar 包的问题

版本回退后,一切正常,所以可以肯定是新版本 jar 包的问题。

3.2 服务启动是否正常

升到新版本继续排查,看了服务进程在,启动日志也正常,查看 tomcat 日志发现报错了。

java.lang.NoClassDefFoundError: com/xxx/.../MarCouponDto
        at java.lang.Class.getDeclaredMethods0(Native Method) ~[?:1.8.0_92]
        at java.lang.Class.privateGetDeclaredMethods(Class.java:2701) ~[?:1.8.0_92]
        at java.lang.Class.getDeclaredMethods(Class.java:1975) ~[?:1.8.0_92]
        at org.springframework.util.ReflectionUtils.getDeclaredMethods(ReflectionUtils.java:606) ~[spring-core-4.2.0.RELEASE.jar:4.2.0.RELEASE]
        at org.springframework.util.ReflectionUtils.doWithMethods(ReflectionUtils.java:518) ~[spring-core-4.2.0.RELEASE.jar:4.2.0.RELEASE]
        at org.springframework.util.ReflectionUtils.doWithMethods(ReflectionUtils.java:504) ~[spring-core-4.2.0.RELEASE.jar:4.2.0.RELEASE]
        at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.determineCandidateConstructors(AutowiredAnnotationBeanPostProcessor.java:241) ~[spring-beans-4.2.0.RELEASE.jar:4.2.0.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.determineConstructorsFromBeanPostProcessors(AbstractAutowireCapableBeanFactory.java:1069) ~[spring-beans-4.2.0.RELEASE.jar:4.2.0.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1042) ~[spring-beans-4.2.0.RELEASE.jar:4.2.0.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:510) ~[spring-beans-4.2.0.RELEASE.jar:4.2.0.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:482) ~[spring-beans-4.2.0.RELEASE.jar:4.2.0.RELEASE]
        at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:305) ~[spring-beans-4.2.0.RELEASE.jar:4.2.0.RELEASE]
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230) ~[spring-beans-4.2.0.RELEASE.jar:4.2.0.RELEASE]
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:301) ~[spring-beans-4.2.0.RELEASE.jar:4.2.0.RELEASE]
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:196) ~[spring-beans-4.2.0.RELEASE.jar:4.2.0.RELEASE]
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:772) ~[spring-beans-4.2.0.RELEASE.jar:4.2.0.RELEASE]
        at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:834) ~[spring-context-4.2.0.RELEASE.jar:4.2.0.RELEASE]
        at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:537) ~[spring-context-4.2.0.RELEASE.jar:4.2.0.RELEASE]
        at org.springframework.web.context.ContextLoader.configureAndRefreshWebApplicationContext(ContextLoader.java:446) ~[spring-web-4.2.0.RELEASE.jar:4.2.0.RELEASE]
        at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:328) [spring-web-4.2.0.RELEASE.jar:4.2.0.RELEASE]
        at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:107) [spring-web-4.2.0.RELEASE.jar:4.2.0.RELEASE]
        at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4939) [catalina.jar:7.0.42]
        at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5434) [catalina.jar:7.0.42]
        at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150) [catalina.jar:7.0.42]
        at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1559) [catalina.jar:7.0.42]
        at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1549) [catalina.jar:7.0.42]
        at java.util.concurrent.FutureTask.run(FutureTask.java:266) [?:1.8.0_92]
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [?:1.8.0_92]
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [?:1.8.0_92]
        at java.lang.Thread.run(Thread.java:745) [?:1.8.0_92]
Caused by: java.lang.ClassNotFoundException: com.xxx.MarCouponDto
        at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1714) ~[catalina.jar:7.0.42]
        at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1559) ~[catalina.jar:7.0.42]
        ... 30 more

3.3 检查新版本 jar 包中的 pom 依赖

看名字,需要找的 MarCouponDto 和升级的 jar 包、和这个服务没有半毛钱关系。
先从 pom 文件中看看有没有相关的依赖。从 pom 中看了相关的依赖,层级很深,没有办法直接找到相关的依赖。
使用 DependencyAnalyzer 搜索相关的依赖,也没搜到。

3.4 录屏 + 断点调试,根据堆栈信息定位问题点

单从堆栈信息也看不出哪里用到了这个类,但可以肯定的是在 Spring 初始化 bean 的时候用到了。
但 Spring 启动要初始化那么多 bean,一个一个的断点要到猴年马月。
这个时候就想到了录屏,调试的时候打开录屏,快速结束。然后再回放视频,看看最后在哪里结束的。

cd1c12df71cc15b16822536e128a04fa.png

通过录屏找到初始化出错的类后,就可以采用条件断点一次定位了。

d12de13ebb7b5d1bb18ff794b094cb92.png

竟然把业务的实现也打到包里了,无语 。。。

3a6701f733a56e549e6d130469fefd33.png

重新定位到断点后,根据堆栈信息往回找到 beanDefinition,因为 beanDefinition 中包含了 class 的 source 信息,可以直接找到这个 class 是在哪个包中被加载的。

96ab9b10571d4340e7c8d54907d540d1.png

3.5 再从 pom 中查看依赖关系

知道了从哪个包依赖后,再次从 DependencyAnalyzer 搜索包名,就能够得到依赖树了。

b68583016d3b4d39e8a3e926a72c4979.png

排除依赖后,再次启动,此错误消失。

扯两句

jar 包中不要依赖无关的内容,尤其还有业务实现,害人又害己。

如果大家都遵守基本的开发规范,就不会把大量时间浪费在处理这类问题上了。

原创不易,多多关注,一键三连,感谢支持!

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值