Как написать синглтон Java EE / EJB? - PullRequest
7 голосов
/ 04 мая 2010

День назад мое приложение было одним EAR, содержащим один WAR, один EJB JAR и пару служебных файлов JAR. В одном из этих служебных файлов у меня был одноэлементный класс POJO, он работал, и все было хорошо с миром:

EAR
 |--- WAR
 |--- EJB JAR
 |--- Util 1 JAR
 |--- Util 2 JAR
 |--- etc.

Затем я создал вторую WAR и обнаружил (сложным образом), что у каждой WAR есть свой собственный ClassLoader, поэтому каждая WAR видит свой отдельный синглтон, и все оттуда выходит из строя. Это не так хорошо.

EAR
 |--- WAR 1
 |--- WAR 2
 |--- EJB JAR
 |--- Util 1 JAR
 |--- Util 2 JAR
 |--- etc.

Итак, я ищу способ создания одноэлементного объекта Java, который будет работать через WAR (через ClassLoaders?). Аннотация @Singleton EJB казалась довольно многообещающей, пока я не обнаружил, что JBoss 5.1, похоже, не поддерживает эту аннотацию (которая была добавлена ​​как часть EJB 3.1). Я что-то пропустил - могу ли я использовать @Singleton с JBoss 5.1? Обновление до JBoss AS 6 сейчас не вариант.

С другой стороны, я был бы так же рад, если бы мне не пришлось использовать EJB для реализации моего синглтона. Что еще я могу сделать, чтобы решить эту проблему? По сути, мне нужно подключить * полуприкладное * приложение к целому ряду других объектов, таких как различные кэшированные данные и информация о конфигурации приложения. В крайнем случае, я уже рассматривал возможность объединения двух моих войн в одну, но это было бы довольно адски.

* Значение: доступно в основном в любом месте выше определенного слоя; на данный момент, в основном в моих WARs - View и Controller (в широком смысле).

Редактировать: Мне действительно следовало бы назвать это Java EE , а не J2EE, не так ли?


Редактировать 2: Еще раз большое спасибо @Yishai за помощь. После некоторых проб и ошибок похоже, что я выяснил, как использовать один ClassLoader в WAR-файлах под JBoss 5. Я подробно излагаю это ниже для себя, и, надеюсь, другие тоже найдут это полезным.

N.B. это несколько отличается от этого в JBoss 4 (см. ответ Ишая или мои ссылки ниже).

Вместо записи jboss-web.xml для каждой WAR и jboss.xml для EJB-JAR уха, поместите файл jboss-classloading.xml в каждую WAR, в том же месте, что и DD (web.xml). Содержимое jboss-classloading.xml должно быть:

<?xml version="1.0" encoding="UTF-8"?>
<classloading
    xmlns="urn:jboss:classloading:1.0"
    name="mywar.war"
    domain="DefaultDomain"
    parent-domain="Ignored"
    export-all="NON_EMPTY"
    import-all="true">
</classloading>

Это следует из JBoss CW здесь , тогда как то, что (я думаю) работает для JBoss 4.x, описано здесь . Более общая информация о загрузке классов JBoss (ing / ers):

Насколько я могу судить, вики-документы сообщества JBoss для JBoss 5 практически отсутствуют по сравнению с JBoss 4.

Ответы [ 5 ]

11 голосов
/ 04 мая 2010

Хотя в спецификации EJB3.1 представлен синглтон, а ваша версия JBoss его не поддерживает, вы можете использовать аннотацию JBoss @Service для создания синглтона. Инструкция здесь . Кроме того, кажется, что у вас есть JBoss, настроенный для изоляции ваших ejb-файлов и войн друг от друга. Вам не нужно этого делать. Вы можете посмотреть тег loader-repository в специфических XML-файлах jboss, чтобы все ваше ухо разделяло один загрузчик классов (или, возможно, по крайней мере две войны делят один загрузчик классов).

При всем этом, я согласен с @duffymo, что синглтон, который разделяет состояние между двумя войнами, - это идея, что вы должны идти, если не убегать.

Редактировать: Что касается синглетонов, я предлагаю вам посмотреть на такие вопросы, как этот (который также имеет некоторый хороший баланс в комментариях).

Идея о том, что объект хранит кэшированное состояние само по себе, является приемлемой, особенно с EJB3, где вы можете вводить свое состояние вместо статической ссылки на него (если вы используете аннотацию @Service, то вы хотите, чтобы JDoss определялся @Depends аннотация). При этом, если бы вы использовали здесь «правильный» синглтон, то я ожидал бы, что ваша единственная проблема с тем фактом, что ваши WAR-файлы имеют два отдельных загрузчика классов, - это дополнительный объем памяти. В противном случае вы попадете в проблемную область синглетонов (где они должны быть инициализированы для использования, все, что их использует, должно гарантировать, что они инициализируются первыми, и, конечно, весь код тесно связан с их инициализацией).

Там, где синглтоны действительно очень плохи, они хранят состояние, так что один класс может изменить состояние, а другой - его забрать. По сути, в EJB-компонентах нет версии 3.1, и даже тогда возникает много проблем с параллелизмом.

Редактировать (далее): Итак, вы хотите использовать репозиторий загрузчика классов. Я использую JBoss 4.2.3, поэтому я не обязательно знаю все входы и выходы JBoss5 (который переписал свой загрузчик классов, хотя говорят, что он почти полностью совместим с предыдущими версиями), однако в 4.2.x по умолчанию ваша конфигурация не вызывает проблемы, потому что все уши, развернутые на сервере, используют один и тот же загрузчик классов («унифицированный загрузчик классов»). Я подозреваю, что сервер, на котором вы развертываете, имеет конфигурацию по-другому, поэтому я не уверен, как с ним взаимодействовать, но вам нужно добавить файл с именем jboss-app.xml в ваше ухо (в то же местоположение, что и application.xml), которое выглядит примерно так:

 <?xml version="1.0"?>
 <!DOCTYPE jboss-app PUBLIC "-//JBoss//DTD J2EE Application 4.2//EN"
        "http://www.jboss.org/j2ee/dtd/jboss-app_4_2.dtd">
 <jboss-app>
      <loader-repository>
      com.yourcomany:archive=yourear
      </loader-repository>
 </jboss-app>

Это для JBoss 4.2. 5.1 имеет теги того же типа, вот xsd . У него та же концепция загрузчика-хранилища.

Что должно быть этим. То есть до тех пор, пока у вас нет эйб-фляги, войны и т. Д., Им это не нужно. Однако для ваших войн (в jboss-web.xml - в том же месте, что и в web.xml) может потребоваться то же самое. В этом случае, если вы называете репозиторий точно таким же образом (если я правильно понимаю - никогда не пробовал сам), они будут использовать один и тот же загрузчик классов. То же самое касается EJB, настроенного в jboss.xml, который находится в том же месте, что и ejb.xml.

Это может сделать это немного яснее.

1 голос
/ 04 мая 2010

Если вы используете Java EE 6, то он поддерживает одноэлементные EJB-компоненты.

1 голос
/ 04 мая 2010

Вы можете использовать MBean и связать его с JNDI, а затем получить его там, где вы хотите его использовать.

MBean может быть развернут в файле .sar

1 голос
/ 04 мая 2010

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

Почему вы хотите это сделать, это реальный вопрос. Похоже, что все ваши приложения будут связаны таким образом. И Google уничтожает синглтон из своих приложений. Почему вы считаете нужным вернуть его?

0 голосов
/ 04 мая 2010

Если это целесообразно, просто возьмите класс, содержащий синглтон, поместите его в JAR, извлеките JAR из EAR и добавьте JAR в загрузчик классов JBoss (через системный путь к классам или какой-то каталог lib) , Это помещает класс в один загрузчик классов, общий для обеих WAR.

Синглтон не сможет ничего "увидеть" в ваших WAR-файлах приложений и т. Д., Так как они находятся в низком загрузчике классов.

Однако ничто не мешает вам внедрить в синглтон (при запуске сервера) фабричный класс, который происходит из WARs и др., И класс TH имеет доступ ко всем классам приложений. Это делает синглтон более простым контейнером.

Но это легко сделать.

Кроме того, если вы сделаете это, убедитесь, что при закрытии приложения все экземпляры, хранящиеся в этом синглтоне, освобождаются. Любая ссылка на класс от синглтона не будет GC'd, когда вы удаляете приложение. Итак, если у вас есть ссылка на ваше приложение, хранящееся в синглтоне, то на сервере хранится ссылка на загрузчик классов синглетонов, а этот загрузчик классов содержит ссылку на ваш класс синглтона, который содержит ссылку на класс ваших приложений, который содержит ссылку на приложения CLASSLOADER, и TH содержит ссылку на все классы в вашем приложении. Не хороший беспорядок, чтобы оставить позади.

...