依赖 jar 没有传递,导致找不到类文件而启动失败了

919 阅读3分钟

前言

最近频繁遇到找不到类文件错误。

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 看下依赖树!

我的实践已经证明了:重启、清缓存、排除依赖都是没用的!