前言
最近频繁遇到找不到类文件错误。
Caused by: java.lang.NoClassDefFoundError:xxx
就这个家伙。
但是我本地启动服务是正常的,前前后后经历了
惊讶
-> 疑惑
-> 烦躁
-> 暴躁
-> 心塞
-> 欣喜
在短短的小半天内,感觉心情像过了一个过山车+大摆锤,结束了,脑袋都是晕的。
关键是本地是正常的!
现在,请跟随我的视角,来看看这个让人心态差点爆炸的异常吧!
遇到问题
在一顿噼里啪啦之后,代码写完,Junit 测试完毕、接口文档 Upload 到 YApi 完毕。果断发布 dev 环境!
直接进入启动重试!(PS:通过发布平台发布的)
这时候第一反应:本地启动一下试试!
web started successfully
本地正常啊!
肯定是我启动姿势不正确,重新发布一下!
实锤了,和启动姿势没关系!
从淡定到暴躁
当然是看启动日志了。
PS: 服务没起来,只能 ssh 到服务器看日志。
Caused by: java.lang.ClassNotFoundException:xxx
Caused by: java.lang.NoClassDefFoundError:xxx
就这俩哥们,类找不到,奇了怪了。
这个类是通过三方 jar 包依赖进来的,我在 IDEA 里面 ⌘ + B
还能进入源码!
这我不禁怀疑是不是因为开发环境使用的 Docker 容器的原因。
发布其他分支,是可以的。
莫非就是因为我引入了一个其他小伙伴提供的 jar,导致我现在用不了!
又是一顿调整依赖!
还不行!
难道是我引入的引来版本不对?
从其他项目找一找怎么用的!
依然不行!
难道是他的 jar 包里面又依赖了很多其他的?
试着 exclusion
掉其他依赖!
依然不行!
是我本地 jar 缓存?
删除本地磁盘上的 jar 试试?
😠😠😠!
解决方案就在灵光一闪
虽然 dev 用的是容器,咱拉不下来 jar 包。但是我可以本地打个包试试!
clean package
得到一个 jar 包
jar -xvf xxx-web-1.0.0-SNAPSHOT.jar
进到 BOOT-INF/lib
里面
% > ls | grep user
竟然啥也没有!
既然是打包没有打进去,那就看一下 mvn 依赖树的问题吧!
解决问题
web 启动失败,是因为 service 添加的依赖,没有传递到 web,所以 web 打包没有打进去那个类。
注意,这里可以正常打包,本地环境可以正常启动。
奇怪吧!
现在进入解决方式:
- 查看 maven 依赖树
进入到 web module,执行以下命令。
mvn dependency:tree>tree.txt
有这么一行错误:
[WARNING] The POM for com.xxx:xxx-xxx-xxx:jar:1.0.1-SNAPSHOT is invalid, transitive dependencies (if any) will not be available, enable debug logging for more details
问题描述的很清晰,依赖传递失败,因为啥依赖传递失败呢?
再开启 debug 打印下错误:
mvn -X dependency:tree>tree.txt
[WARNING] The POM for com.xxx:xxx-xxx-xxx:jar:1.0.1-SNAPSHOT is invalid, transitive dependencies (if any) will not be available: 2 problems were encountered while building the effective model for com.xxx:xxx-xxx-xxx:jar:1.0.1-SNAPSHOT
[ERROR] 'dependencies.dependency.version' for com.alibaba:easyexcel:jar is missing. @
[ERROR] 'dependencies.dependency.version' for com.xxx:cache:jar is missing. @
说是因为下面两个 jar 的 version 找不到,所以会导致依赖传递失败。
PS: 我所有的依赖版本都是在父 POM 进行维护的,子 module 只有依赖 groupId 和 artifactId。
所以归根到底,是因为父 POM 的版本没有传递下去!
仔细一瞅,发现父 POM 的版本是 1.0.0,各个 module 的 parent
节点的属性也是 <version>1.0.0</version>
。
之前都是 SNAPSHOT 版本,后来因为公司的 nexus 配置了自动清除长时间不用的 SNAPSHOT 版本的依赖,我就去掉了 SNAPSHOT。
父 POM deploy 到私服的就是一个空的项目,里面就一个 POM 文件。
最后升级了一下父 POM 的版本,重新 deploy 一下,再改改各个 module 的依赖版本。
大功告成!
总结
本文主要是含泪记下一个苦逼的问题排查过程。害,竟然没有第一时间想到原因!
下次再遇到记得 mvn -X dependency:tree>tree.txt
看下依赖树!
我的实践已经证明了:重启、清缓存、排除依赖都是没用的!