Как работает загрузка классов, когда один и тот же класс существует в разных приложениях на одном сервере? - PullRequest
31 голосов
/ 09 ноября 2010

У меня несколько веб-приложений, работающих на сервере приложений, и каждый WAR-файл веб-приложения содержит копию одного и того же файла JAR.

Означает ли это, что класс в этом файле JAR будет загружен несколькораз в JVM, один раз для каждого файла WAR, в котором он существует?Исходя из этого, если у меня есть статический синхронизированный метод в таком классе, он синхронизируется только между потоками в веб-приложении, в котором он существует, но не синхронизирован с тем же методом в том же классе в другом файле JAR в другомФайл WAR?(Надеюсь, что вопрос имеет смысл, уточню при необходимости).

Если это так, я предполагаю, что лучшим решением будет удалить файл jar из каждого файла WAR и развернуть его в общей папке classpath на сервере.

Ответы [ 3 ]

33 голосов
/ 09 ноября 2010

Загрузчик классов Java обычно работает, ища классы в одном или нескольких местах в фиксированной последовательности. Например, загрузчик классов, который загружает ваше приложение при запуске из командной строки, сначала ищет в файле rt.jar (и других в bootclasspath), а затем в каталогах и файлах JAR, указанных вашим classpath.

Загрузка классов веб-приложений в принципе похожа, но на практике немного сложнее. Для конкретного веб-приложения загрузчик классов веб-приложения ищет классы в следующем порядке. Например, Tomcat 6 ищет классы в следующем порядке:

  1. Начальные классы вашей JVM
  2. Классы загрузчика системных классов (описано здесь )
  3. / WEB-INF / классы веб-приложения
  4. / WEB-INF / lib / *. Jar веб-приложения
  5. $ CATALINA_HOME / Lib
  6. $ CATALINA_HOME / Библиотека / *. Баночка

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

Сложность состоит в том, что у веб-контейнера есть один загрузчик классов для каждого веб-приложения, и эти загрузчики классов делегируют другим загрузчикам классов, которые управляют общими классами. На практике это означает, что некоторые классы будут загружаться только один раз для всего контейнера (например, 1. и 2.), а другие могут загружаться несколько раз разными загрузчиками классов.

(Когда класс загружается более одного раза, это приводит к отдельным Class объектам и разным статическим классам. Версии класса имеют разные типы в том, что касается JVM, и вы не можете выполнить приведение типов из одной версии в др.)

Наконец, Tomcat можно настроить для «горячей загрузки» отдельных веб-приложений. Это влечет за собой остановку веб-приложения, создание для него нового загрузчика классов и его перезапуск.

Followup

Итак ... синхронизация статического метода не защитит доступ к общему ресурсу, где класс был загружен несколько раз?

Это зависит от деталей, но, вероятно, не будет. (Или, если посмотреть по-другому, если класс на самом деле был загружен несколько раз, то метод static каждой "загрузки" класса будет обращаться к другому набору static полей. )

Если вы действительно хотите, чтобы экземпляр класса одиночного приложения совместно использовался несколькими веб-приложениями в одном контейнере, проще всего поместить класс в $CATALINA_HOME/lib или его эквивалент. Но вы также должны спросить себя, хороший ли это дизайн системы. Рассмотрите возможность объединения веб-приложений или использования переадресации запросов и т. Д. Вместо общей структуры данных. Шаблон синглтона может быть проблематичным в веб-приложениях, и этот аромат тем более.

4 голосов
/ 09 ноября 2010

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

Вы получаете шаблоны, такие как несколько файлов WAR и один файл EJB в EAR с иерархией загрузчиков классов, каждая из которых имеет свою собственную.

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

Некоторые серверы приложений (например, WebSphere) явно поддерживают концепцию общей библиотеки, и я ее использую.

Остерегаясь просто вставлять JAR-файлы в произвольные пути к классам, вы рискуете дестабилизировать сам сервер приложений.

0 голосов
/ 09 ноября 2010

Большинство серверов приложений используют , наиболее специфичные для пути, имеют приоритет политика. Если у вас есть несколько библиотек, которые делают одно и то же, вы должны поместить их в библиотеку сервера приложений (например, TOMCAT_HOME / lib)

...