java - 为什么更改 WEB-INF/lib 中 jar 文件的目录顺序会导致 Tomcat 8 中出现 NoClassDefFoundError?
问题描述
我们有一个在 Tomcat 8 中运行的 Web 应用程序,最近我们观察到我们团队中的一些开发人员构建的工件(.war 文件)抛出一个 .war 文件NoClassDefFoundError
,而其他人构建的相同代码按预期运行。
来自logs/localhost.2018-05-11.log
:
org.jboss.resteasy.spi.UnhandledException: java.lang.NoClassDefFoundError: Could not initialize class org.geotools.referencing.datum.DefaultEllipsoid
...
Caused by: java.lang.NoClassDefFoundError: Could not initialize class org.geotools.referencing.datum.DefaultEllipsoid
at org.geotools.referencing.GeodeticCalculator.<init>(GeodeticCalculator.java:277)
...
这有时但并非总是伴随(之前):
org.jboss.resteasy.spi.UnhandledException: java.lang.IncompatibleClassChangeError: Implementing class
...
检查 war 文件,工作和损坏的工件的内容似乎是相同的,除了一个值得注意的例外,jar 文件的“目录顺序”WEB-INF/lib
不同。
对已分解的 war 文件执行以下过程并重新启动 Tomcat 似乎可以消除异常:
$ # jars in "bad" order
$ ls -U WEB-INF/lib
x.jar
b.jar
y.jar
a.jar
c.jar
z.jar
$ cp -p WEB-INF/lib/* /tmp/lib/
$ rm -r WEB-INF/lib
$ mv /tmp/lib WEB-INF/lib
$ # jars in "good" order (appears to be alphabetical after a 'cp' on my system)
$ ls -U WEB-INF/lib
a.jar
b.jar
c.jar
x.jar
y.jar
z.jar
“好”的战争没有按字母顺序排列的罐子,但似乎有许多“好”的订单和一些“坏”的订单。
我最初认为我们可能DefaultEllipsoid
在不同的 jar 中有多个版本的类,导致正确版本和另一个版本之间出现竞争条件,但似乎并非如此。
我在 tomcat 中启用了详细的类加载器调试,在这两种情况下,都logs/catalina.out
显示这个类是从正确的 jar 加载的:
[Loaded org.geotools.referencing.datum.DefaultEllipsoid from file: /opt/tomcat/temp/1-webapp/WEB-INF/lib/gt-referencing-11.4.jar]
知道这里可能会发生什么吗?
细节:
- CentOS 7
- Apache Tomcat/8.0.43
- Java 1.8.0_144
- 阿帕奇 Maven 3.3.9
解决方案
该行:
Caused by: java.lang.NoClassDefFoundError: Could not initialize class org.geotools.referencing.datum.DefaultEllipsoid
表示该类DefaultEllipsoid
已找到但有效,还有一些其他类需要加载但失败。另一个类是无效的。
正是这个类可能与两个非常不同的版本重复,或者一个版本用于编译,另一个版本在运行时具有不同的方法签名。
此外,从 tomcat8 开始,不再按字母顺序加载其中的应用程序jar文件WEB-INF/lib
。我认为在 tomcat 网站上有一个文档,但现在我找不到它了,但我在tomcat bugzilla bug 57129上发现了一个回归错误(不会修复)
这个类加载器的东西意味着如果你改变一些东西WEB-INF/lib
并重新启动 Tomcat,那么如果有重复的 jar 版本,就会有一些随机的类加载使你的应用程序以一种或另一种方式加载。
总结一下:检查DefaultEllipsoid
导入并检查这些类是否有重复项。您的构建还需要清理以使用与运行时相同的版本(我希望您使用类似maven
进行构建的工具)
推荐阅读
- java - 使用库导出 Gradle 项目
- github - 使用 GitHub Web 界面显示分支之间的差异
- c++ - 上下文相关的模板参数推导 - 参数的类型/值不匹配
- docker - 运行 docker-compose.yml 后,许多站点出现错误“无法访问此站点”
- jquery - 如何使用下拉菜单更改数据输入掩码前缀
- android - I/system_server:单向函数结果将被丢弃,但以状态 OK 和包裹大小 4 完成
- python - 为什么我无法在 tkinter 中找到或输入已添加到文件的条目?
- javascript - 下一个 js 404 页面不起作用。可能是什么问题呢?
- excel - 如何使用excel转换间隔中的句子?
- git - Git - 删除存储库后拒绝推送初始代码