Jboss 5, загрузчик классов и несколько экземпляров класса

#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 ) Я надеюсь, что эта информация кому-то поможет.