Порядок загрузки классов из .war файла

У меня есть вопрос относительно гарантий, если таковые имеются, в следующем сценарии (обратите внимание, что вопрос не "Как это сделать по-другому?", вопрос действительно о порядке загрузки классов в следующем (лучше понять, как работает загрузка классов).

Вот гипотетический сценарий... Там есть .war файл, который имеет следующую (частичную) структуру каталогов:

 WEB-INF/classes/com/acme/Bunny.class
 .
 .
 .
 WEB-INF/lib/acme.jar

Оба файла Bunny.class имеют импорт, ссылающийся на другие классы из acme.jar

Bunny.class в WEB-INF/classes/... является единственным классом, который имеет то же имя/путь, что класс из acme.jar.

Файл .jar acme.jar также содержит com.acme.Bunny(и нет специальных трюков загрузчика класса).

Я понимаю, что спецификация Java гарантирует, что класс не будет загружен до тех пор, пока он не будет использован (или "вручную загружен классом" специально) программой, поэтому, если вы используете тысячи .jar, скажем, в .war, classloader (s) не запускают загрузку классов десятками тысяч классов.

(редактировать)

Но как насчет порядка, в котором два класса в приведенных выше примерах загружен?

должен быть сформулирован:

Но как решено, какая из загружены два класса выше?

или что-то в этом роде:)

Там одна гарантия сделана: com.acme.Bunny должен использоваться перед любым другим классом из com.acme....

В принципе, в Википедии написано:

Самые сложные проблемы с JAR hell возникают в обстоятельствах, которые Преимущество полной сложности система загрузки классов. Java программе не требуется использовать только один "плоский" загрузчик классов, но вместо этого может состоять из нескольких (или в факт, неопределенное число) вложенных, взаимодействующих загрузчиков классов. Классы загруженные разными загрузчиками классов, могут взаимодействовать сложными способами не полностью понятный разработчиком, ведущий к необъяснимым ошибкам или ошибкам.

Итак, мне интересно: могу ли я быть уверенным, что /classes/com/acme/Bunny.class будет загружаться по классу до того, как из .jar в WEB-INF/lib/dir или нет?

Ответы

Ответ 1

Этот вопрос может быть полезен.

Спецификация сервлета неясна. Можно было бы ожидать, что "WEB-INF/classes" будет обыскаться до "WEB-INF/lib", но кажется, что это нужно для контейнера сервлетов. Все, что вы можете быть уверены в том, что контейнер должен последовательно загружать один за другим, так что вы никогда не должны видеть оба класса в одном контейнере. Путь поиска может быть настроен в зависимости от вашего контейнера.

Извините, я не могу быть более конкретным: добро пожаловать в мир нескольких контейнеров сервлетов. Не заставляйте меня начинать с веселых игр в Websphere.

Ответ 2

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

Servlet 2.4: http://download.oracle.com/otn-pub/jcp/servlet-2.4-fr-spec-oth-JSpec/servlet-2_4-fr-spec.pdf - раздел SRV.9.5, последний абзац

Servlet 3.0: http://download.oracle.com/otn-pub/jcp/servlet-3.0-fr-oth-JSpec/servlet-3_0-final-spec.pdf - раздел 10.5, последний абзац

загрузчик классов Web-приложений должен загружать классы из WEB-INF/classes сначала, а затем из библиотеки JAR в каталоге WEB-INF/lib.

Ответ 3

Оба файла WEB-INF/lib/*.jar и каталог WEB-INF/classes находятся в одном классе ClassLoader. Было бы так, как если бы вы запустили приложение со всеми баночками, перечисленными в ClassPath. Поскольку имя класса необходимо разрешить, ClassLoader найдет первый класс, который соответствует его ресурсам. Точный порядок поиска в нем недетерминирован - это зависит от платформы.

Пакеты Java были разработаны для решения проблемы конфликтов имен, таких как описанные вами. Никогда не рекомендуется преднамеренно назвать класс таким же, как тот, который содержится в его собственном файле jar. Лучшим решением будет расширение класса и использование новой версии в вашем коде. Если вам нужно изменить функциональность этого класса, вы можете изучить черную магию Java-ориентированного программирования.

Ответ 4

Ответ полностью зависит от конкретной иерархии загрузчика классов. В то время как JVM предоставит загрузчик системного класса, серверы приложений Java EE обычно используют пользовательские ClassLoader для изоляции классов, загружаемых в отдельные модули и приложения, и для обеспечения безопасности.

API ClassLoader не навязывает никаких правил, как конкретные реализации разрешают запросы класса. Однако целью каталога WEB-INF/lib является предоставление связывания библиотек приложений. Я подозреваю, что большинство людей ожидают, что файлы jar в каталоге lib будут найдены ПОСЛЕ корневого содержимого файла jar.

Я не знаю, что спецификации Java EE устанавливают любую такую ​​гарантию, но интерфейс и документация для абстрактного класса ClassLoader, конечно же, не делают.

Итак, предположительно, у вас может быть веб-контейнер, который в конечном итоге вернет Bunny.class из файла jar, а не из корневой иерархии военного файла.

Ответ 5

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

Классы загружаются сразу после развертывания развертывания войны в контейнер. Обычно, когда сервлет сервера загрузчика контекста загружается, а остальная часть приложения - с ним. Это можно сделать разными способами, например, ссылкой на сервлет по умолчанию или загрузкой контекста spring и т.д.

Чтобы WEB-INF/classes/com/acme/Bunny.class был загружен первым afaik.

Ответ 6

Вы, кажется, объединяете два разных чувства "раньше".

Классы загружаются в том порядке, в котором они используются. Это временное и более правильное использование "до". Если Foo используется до Bar, то он будет загружен перед Bar.

Вы также говорите о том, будут ли загружаться классы /com/acme/Bunny.class "до" acme.jar com/acme/Bunny.class. Второй не будет загружен вообще. Классный загрузчик будет искать первый экземпляр com/acme/Bunny.class в пути к классам, найти его в классах и перестать искать.