#java #jboss #dependencies
#java #jboss #зависимости
Вопрос:
У меня возникла проблема с моим приложением. Чтобы возобновить проблему, мне пришлось перенести приложение с jboss 4 на jboss 5.
Во время развертывания war у меня возникла эта ошибка:
java.lang.LinkageError: loader constraint violation: when resolving field "DATETIME"
the class loader (instance of org/jboss/classloader/spi/base/BaseClassLoader) of the referring class,
javax/xml/datatype/DatatypeConstants, and the class loader (instance of <bootloader>)
for the field's resolved type, javax/xml/namespace/QName,
have different Class objects for that type
После многих поисков я обнаружил, что эта ошибка была здесь, потому что у меня несколько раз был один и тот же класс в разных пакетах. Однажды в пакете зависимостей (из моего pom.xml ) и однажды предоставленный jboss.
Итак, чтобы решить эту проблему, я предоставил область видимости для моей зависимости.
Но я не понимаю, почему это решение работает. Я думал, что это работает, чтобы иметь несколько раз один и тот же класс в приложении. Я знаю, что это не очень хорошо, но с jboss 4 это работает.
Кто-нибудь может объяснить мне, почему это работает с jboss 4, а не с jboss 5.
Спасибо за ваше объяснение 🙂
Комментарии:
1. Что это за класс, который повторяется? В какие пакеты это повторяется?
2. где вы устанавливаете <область>, предоставленную</scope>, спасибо
Ответ №1:
То, что вы видите, является результатом того, что сервер приложений загружает библиотеки JBoss и EAR-библиотеки в отдельные загрузчики классов
Вы можете представить иерархию загрузчика классов EAR аналогичной (но не обязательно) :
Загрузчик классов начальной загрузки -> Загрузчик системных классов -> Загрузчик системных классов JBoss -> Загрузчик классов Ear -> Загрузчик классов War.
Где родительским элементом загрузчика класса war является загрузчик класса ear и так далее.
Теперь, если в загрузчике классов Bootstrap загружен jar A и ear также развертывается с jar A, загрузчик классов Bootstrap и загрузчик классов Ear будут иметь один и тот же класс, созданный дважды в разных загрузчиках классов.
Я бы предположил (не уверен в этом на 100%), что JBoss 4 не поставляется в комплекте с javax / xml / namespace / QName. Если это так, то JBoss 5, скорее всего, является другой, обновленной версией Java (4 -> 5 или 5 -> 6). В результате (с новым JBoss 5), когда вы пытаетесь передать javax / xml / namespace / QName в один из ваших классов, он ожидает класс из ear. Однако вы предоставляете ему класс QName из загрузчика классов начальной загрузки из-за настроек загрузчика классов (сначала родительский и так далее).
Поскольку типы классов равны, но экземпляры классов не равны, вы получаете ошибку LinkageError
Редактировать:
Только два адресуют два комментария —
Поведение при загрузке классов, как отметил Талборн, определенно отличается. В обычных приложениях системные классы, такие как QName, будут последовательно просматриваться в загрузчике классов начальной загрузки. В вашей ошибке это выглядит так, как будто javax / xml / datatype / DatatypeConstants загружается в org / jboss / classloader / spi / base / BaseClassLoader. Давайте предположим, что это загрузчик классов EAR (или WAR). Быстрый поиск в Google показывает, что это часть семейства xml-api и, возможно, jaxp-api.
Итак, где-то в вашем коде (или коде другой библиотеки, расположенной в загрузчике классов EAR) требуются DatatypeConstants, что приводит к принудительному поиску класса в classloader EAR. Создание объекта QName, однако, загрузило класс из загрузчика классов начальной загрузки (вместо EAR). Это произойдет, если класс QName уже был инициализирован системой, что, вероятно, так и есть.
Этого, как вы можете себе представить, не должно произойти. На самом деле похоже, что у вас есть parent-last. Поскольку при загрузке класса из механизма загрузки классов JBoss, если бы был включен параметр parent-first, исходные DatatypeConstants возвращали бы родительские (bootstrap) DatatypeConstants, а не дочерние. Итак, как отметил jtahlborn, вы хотели бы, чтобы дочерний classloader здесь игнорировался.
Что касается разрешения, если только вам не нужны зависимости по определенной причине (например, немного более новая версия лучше текущей) Я бы делегировал реализацию jboss. Если это не так, вы можете взглянуть на class-loading java2ClassLoadingCompliance
элемент, который есть в конфигурации jboss.
Комментарии:
1. я думаю, что это близко, но не совсем правильно. как правило, загрузчики классов war настроены так, чтобы отдавать предпочтение загрузке из дочернего элемента. в противном случае вы бы никогда не увидели конфликт, поскольку версия класса в war была бы проигнорирована. вы правы, что наиболее вероятной проблемой является разница в версии java (я сомневаюсь, что jboss включает классы jaxb).
2. Что я узнал при обновлении websphere и weblogic до более новых версий (которые включали более новые версии Java), так это то, что среды выполнения Java включали собственный javax / xml / namespace / QName и связанные библиотеки. Я думаю, это проблема с OP. И да, вы правы, конфигурация по умолчанию обычно предполагает, что parent-last является последним.
3. следует уточнить, что в этом сценарии поведение при загрузке классов отличается , поскольку именно это сбивает с толку OP. в «обычных» приложениях Java повторяющиеся классы, включенные в дочерний classloader, игнорируются.
4. Как вы настраиваете конфигурацию в parent-last?
5. о вашей правке. На самом деле, я пробовал соответствие загрузчика классов java2ClassLoadingCompliance, но при этом у меня появилась новая ошибка о конфигурации регистратора. И, наконец, для моего приложения лучше использовать jboss по умолчанию. Большое спасибо за ваше очень полное объяснение 🙂
Ответ №2:
-verbose:class
в аргументах виртуальной машины будет указано, как загружается класс. Если есть дубликат, вы можете удалить конфликтующий jar / jars’ы.
Ответ №3:
Спасибо за объяснение — это было очень полезно.
Я узнал, что эта проблема связана с ошибкой JBoss, которая была исправлена в выпуске 5.0.0. Но даже несмотря на то, что я использую более старую версию JBoss, я все еще получаю эту ошибку. В любом случае, я провел обширное исследование и несколько раз запускал дерево зависимостей maven, чтобы увидеть, откуда берутся повторяющиеся определения. Я, наконец, смог устранить эту ошибку, добавив две зависимости — с областью видимости, установленной на предоставленную — в мой основной pom:
(sun.jaxb-impl 2.1 , javax.jaxb-api 2.2 ) Я надеюсь, что эта информация кому-то поможет.