Среда, БЫЛ 6.1 на Linux, развертывая веб-приложение, которое использует классы от xercesImpl.jar.
Из-за ограничений политики компании, приложение должно быть развернуто с настройками:
Class Loader Order
Classes loaded with parent class loader first
-> Classes loaded with application class loader first
WAR class loader policy
Class loader for each WAR file in application
-> Single class loader for application
ВОЕННЫЙ файл содержит копию xercesImpl.jar, тот же, который был в пути к классу, когда приложение было скомпилировано.
При запуске веб-приложения, когда Spring пытается проанализировать свои конфигурации, он бросает:
java.lang.VerifyError: class loading constraint violated
(class: org/apache/xerces/jaxp/DocumentBuilderImpl
method: parse(Lorg/xml/sax/InputSource;)Lorg/w3c/dom/Document;)
АНАЛИЗ ДО СИХ ПОР
Кажется, что это БЫЛО, обеспечивает реализацию org.apache.xerces.jaxp. DocumentBuilderImpl, потому что мы можем удалить xercesImpl.jar из ВОЕННОГО файла и все еще получить ту же ошибку (не ClassNotFoundException). Таким образом БЫЛ, кажется, разрешает ссылки с помощью его собственной копии, которая является несовместимой со ссылками в наших компилируемых файлах класса. Однако единственный другой экземпляр 'xercesImpl.jar', который я могу найти (кроме копии, развернутой с нашим приложением), находится в каталоге deploytool
, который, кажется, вне сервера приложений.
Я просканировал все банки в, БЫЛ (весь 1300 их) с
for i in `find . -name \*.jar`; do jar tvf $i|grep -qi xerces && echo $i ; done
и найденный этим ./java/jre/lib/xml.jar
содержит все классы в org.apache.xerces.*
, таким образом, это вероятно, где classloader разрешает ссылку.
ВОТ СТРАННАЯ ЧАСТЬ:
Если мы изменяемся на "загрузчик родительского класса сначала", мы не видим исключение. Это идет в противоречии с ожидаемым поведением. Мы ожидали бы, что с "приложением classloader сначала" это будет использовать xercesImpl.jar, что мы, если, и используют версию WAS, только если мы устанавливаем "родителя classloader сначала". Это, кажется, назад от того, что мы на самом деле видим.
ВОПРОС:
Как classloader делегация устанавливает взаимодействие с вышеупомянутой информацией для приведения к наблюдаемому поведению?
Ваша WAR также включает классы org.xml.sax или org.w3c.dom, а затем вы ссылаетесь на класс за пределами вашего приложения, который также ссылается на эти классы. Это создает сценарий, в котором загрузчик классов вашего приложения видит два экземпляра одного и того же класса, что является ошибкой связывания.
Например, если ваше приложение использует javax.xml.bind.Unmarshaller.unmarshal (InputSource), то Unmarshaller будет загружен из JDK, а класс Unmarshaller будет виден только для JDK InputSource. Когда ваше приложение создает свой InputSource, оно загружает класс из WAR (потому что политика «сначала приложение»), а затем ваше приложение пытается передать экземпляр WAR InputSource в JDK Unmarshaller, который может принимать только экземпляр JDK InputSource.
Есть два решения:
По моему опыту, ошибки связывания довольно сложно отследить, потому что JVM дают скучную информацию о том, что вызывает добавление ссылок.Обычно я включаю трассировку загрузчика классов, воспроизводю проблему, а затем иду назад, пока не найду класс, загруженный извне приложения, который "звучит так", как будто он может ссылаться на класс, который, как известно, существует внутри приложения.
Если мы изменим на «загрузчик родительского класса во-первых, мы не видим исключения. Это противоречит ожидаемому поведение.
Да, верно, это единственный способ увидеть такое поведение. Я могу посоветовать вам взглянуть на "Вы действительно получаете загрузчики классов?" говорить, так как на ваш вопрос нет однозначного или короткого ответа.
http://www.slideshare.net/guestd56374/do-you-really-get-class-loaders http://www.parleys.com/#sl=2&st=5&id=1585