Почему изменение порядка каталогов файлов jar в WEB-INF/lib вызывает NoClassDefFoundError в Tomcat 8?

у нас есть веб-приложение, которое мы запускаем в Tomcat 8, и недавно мы заметили, что артефакты (.war files) построен некоторыми разработчиками в нашей команде throw a 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
    ...

изучая военные файлы, содержимое рабочих и сломанных артефактов кажется идентичным, с одним заметным исключение, "порядок каталогов" файлов jar в WEB-INF/lib разное.

выполнение следующей процедуры для взорванного файла войны и перезапуск 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 класса в разных банках, вызывая условие гонки между правильной версией и другой версией, но это, похоже, не так.

Я включил подробную отладку загрузчика классов в tomcat, и в обоих случаях logs/catalina.out показывает, что этот класс загружается из правильной банки:

[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
  • Apache Maven 3.3.9

4 ответов


строку:

Caused by: java.lang.NoClassDefFoundError: Could not initialize class org.geotools.referencing.datum.DefaultEllipsoid

означает, что класс DefaultEllipsoid найдено, но чтобы быть действительным, есть некоторые другой класс это нужно загрузить, но это не удастся. Другой класс недопустим.

именно этот класс, возможно, дублируется с двумя очень разными версиями, или одна версия используется для компиляции, другая версия с другой сигнатурой метода во время выполнения.

кроме того, из tomcat8, прикладные файлы jar в WEB-INF/lib несколько не загружается в алфавитном порядке больше. Я думаю, что на сайте tomcat был документ с этим, но сейчас я его больше не нахожу, но я нашел ошибку регрессии (не исправлю) на tomcat bugzilla ошибка 57129

этот материал classloader означает, что если вы измените некоторые вещи на WEB-INF/lib и перезапустить Tomcat, то есть немного случайной загрузки класса, которые делают вашу загрузку приложения так или иначе, если есть дубликат jar версия.

подводя итог: Проверьте DefaultEllipsoid import и проверьте, есть ли дубликат в этом классе. Ваша сборка также должна быть очищена, чтобы использовать ту же версию, что и среда выполнения (надеюсь, вы используете такие инструменты, как maven делать сборку)


по просьбе K. Sopheak и amod (модераторы), я обновляю.

существует одна причина для этого исключения, связанная с временным каталогом Tomcat.

временные файлы из предыдущего развертывания может вызвать это. Проверьте workDir (значение по умолчанию : $TOMCAT_BASE/work), и когда Tomcat остановлен, очистите его, удалив все.


порядок банок действительно будет иметь значение. в основном загрузчик классов загружает их таким образом. Поэтому, когда есть несколько версий одного и того же класса, вы можете получить этот NoClassdefFoundError или java.ленг.IncompatibleClassChangeError: Он может видеть вас классы, но путают, какой из них использовать или классы модифицируются и помещаются в несколько банок. Проверьте свои банки, если есть какие-либо дубликаты классов, то вы можете устранить основную причину.


на подобный вопрос было дано несколько интересных ответов что вызывает IncompatibleClassChangeError предполагая, что вы и другие разработчики не используете одни и те же файлы jar во время компиляции. Сравните (по крайней мере, размер файла, но контрольная сумма будет лучше) каждый файл jar, используемый для компиляции, и снова те, которые используются во время выполнения, конечно, те, которые вы используете сами и те, которые используются другими разработчиками.