Maven 依赖版本范围引发的 NoClassDefFoundError 问题排查
Maven 依赖版本范围引发的 NoClassDefFoundError 问题排查
1. 问题现象
在开发环境中,一个 Java 应用重新打包后重启提示 java.lang.NoClassDefFoundError: com/ibm/icu/util/Calendar
异常。
具体错误日志如下:
java.lang.NoClassDefFoundError: com/ibm/icu/util/Calendar
at java.lang.Class.getDeclaredMethods0(Native Method)
at java.lang.Class.privateGetDeclaredMethods(Class.java:2701)
at java.lang.Class.getDeclaredMethod(Class.java:2128)
at java.io.ObjectStreamClass.getPrivateMethod(ObjectStreamClass.java:1575)
at java.io.ObjectStreamClass.access$1700(ObjectStreamClass.java:79)
at java.io.ObjectStreamClass$2.run(ObjectStreamClass.java:508)
at java.io.ObjectStreamClass$2.run(ObjectStreamClass.java:482)
at java.security.AccessController.doPrivileged(Native Method)
at java.io.ObjectStreamClass.<init>(ObjectStreamClass.java:482)
at java.io.ObjectStreamClass.lookup(ObjectStreamClass.java:379)
at java.io.ObjectStreamClass.lookup(ObjectStreamClass.java:223)
at org.apache.mina.core.buffer.AbstractIoBuffer$3.readClassDescriptor(AbstractIoBuffer.java:2191)
.....
2. 分析
错误信息显示,启动过程中无法找到 ICU4J 库中的 Calendar 类。按照往常的经验就是这两种:
- 缺少必要的 jar 包。
- 存在版本不匹配的问题。
3. 排查
这个 Java 应用的 JAR 包是单独放置在同目录下的 lib 目录下, 查看 lib 目录下相关的 JAR 包, 发现存在以下版本的 ICU4J :
icu4j-68.2.jar
icu4j-69.1.jar
icu4j-70.1.jar
看着也是有 JAR 包的,不至于找不到。于是怀疑打出来的包有问题,然后重新打了一个包上去,启动还是报这个错。
那就只能看 JAR 包启动的时候依赖的是哪个版本了。 解压应用 jar 包:
$ jar xf application.jar
然后找到 META-INF\MANIFEST.MF
文件:
文件的大概内容如下:
Manifest-Version: 1.0
Implementation-Title: app name
Implementation-Version: 2.0
Built-By: root
Specification-Title: app name
Implementation-Vendor-Id: com.xxx
Class-Path: ..... lib/icu4j-71.1.jar ......
Main-Class: com.xxx.xxx.Main
Build-Time: xxxx-xxxx-xxxT09:43:03Z
Created-By: Apache Maven
Build-Jdk: 1.8.0_171
Specification-Version: 2.0
Implementation-URL: http://xxx.xxxx.com
从这个里面看到了,需要的是 icu4j-71.1.jar 这个包,可以看到 lib 目录下没有这个包。正常情况下更新了版本应该会把包给替换的,那就只能去代码里面查看下了。
检查 pom.xml 依赖配置:
<dependency>
<groupId>com.ibm.icu</groupId>
<artifactId>icu4j</artifactId>
<version>[63.1,)</version>
<optional>true</optional>
</dependency>
注意这里的版本号:
- 版本范围
[63.1,)
允许 Maven 使用63.1
或更高版本的icu4j
。 - 这种开放的版本范围,没有上限, Maven 会尽可能使用最新的稳定版本。
坑就在这里,每次都是用最新的版本 JAR 包,一旦哪天忘记更新包到 lib 目录下 ,应用就容易出现这个问题。
4. 解决
上传 icu4j-71.1.jar 到 lib 目录下,重启应用就正常了。
4. 总结
- pom.xml 中就不应该使用这种开放范围的版本,固定一个版本即可。