我们有一个在Tomcat 8中运行的Web应用程序,最近我们发现我们团队中的一些开发人员构建的工件(.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文件,工作和损坏的工件的内容看起来是相同的,有一个值得注意的例外,&#34;目录排序&#34; WEB-INF/lib
中的jar文件不同。
对爆炸的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
&#34; good&#34;战争没有按字母顺序排列,但似乎有很多好的&#34;订购了一些&#34;坏&#34;订单。
我最初认为我们可能在不同的jar中有多个版本的DefaultEllipsoid
类,导致正确版本和另一个版本之间出现竞争条件,但似乎并非如此。
我在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]
对这里可能发生的事情有所了解吗?
详细说明:
答案 0 :(得分:1)
该行:
Caused by: java.lang.NoClassDefFoundError: Could not initialize class org.geotools.referencing.datum.DefaultEllipsoid
表示已找到类DefaultEllipsoid
但有效,有一些其他类需要加载,但这会失败。另一个类无效。
这个类可能与两个非常不同的版本重复,或者一个版本用于编译,另一个版本在运行时使用不同的方法签名。
另外,从tomcat8开始,WEB-INF/lib
中的应用jar文件已经按照字母顺序加载 NOT 了。我想在tomcat网站上有一个这样的文件,但是现在我不再找到了它,但我在tomcat bugzilla bug 57129
这个类加载器的东西意味着如果你改变WEB-INF/lib
上的一些东西并重新启动Tomcat,那么有一些随机的类加载会使你的应用程序以一种方式加载,如果有重复的jar版本。
总结:检查DefaultEllipsoid
导入并检查这些类是否有重复。您的构建还需要清理以使用与运行时相同的版本(我希望您使用maven
之类的工具来构建)
答案 1 :(得分:0)
按照K. Sopheak和amod(主持人)的要求,我更新。
此异常有一个原因,与Tomcat临时目录有关。
来自先前部署的 临时文件可能会导致此问题。检查workDir(默认值:$TOMCAT_BASE/work
),当Tomcat停止时,通过删除所有内容来清理它。
答案 2 :(得分:0)
罐子的顺序真的很重要。 基本上类加载器以这种方式加载它们。 因此,当同一个类有多个版本时,您可能会遇到NoClassdefFoundError或java.lang.IncompatibleClassChangeError: 它能够看到你的类,但是对于使用哪一个或者修改了类并放置在多个jar中感到困惑。检查您的罐子是否有任何重复的类,然后您可以消除根本原因。
答案 3 :(得分:0)
在类似的问题What causes IncompatibleClassChangeError上给出了几个有趣的答案,表明您和其他开发人员在编译时没有使用相同的jar文件。比较(至少文件大小,但校验和会更好)每个用于编译的jar文件,以及运行时使用的文件,当然是你自己使用的文件和其他开发人员使用的文件。 / p>