Как я пишу Java Singleton EE/EJB?

День назад моим приложением был один EAR, содержа одну ВОЙНУ, один JAR EJB и несколько файлов утилиты JAR. У меня был singleton-класс POJO в одном из тех служебных файлов, он работал, и все было хорошо с миром:

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

Затем я создал вторую ВОЙНУ и узнал (твердый путь), что каждая ВОЙНА имеет свой собственный ClassLoder, таким образом, каждая WAR видит различный одиночный элемент и вещи повреждение по сравнению с там. Это не настолько хорошо.

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

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

Поочередно, я был бы так же рад не должным быть использовать EJB для реализации моего одиночного элемента. Что еще я могу сделать для решения этой проблемы? В основном мне нужен semi-application-wide* рычаг в целый набор других объектов, как различные кэшированные данные и информация о конфигурации приложения. Как последнее прибежище я уже рассмотрел слияние моих двух ВОЙН в одну, но это было бы довольно адским.

*Значение: доступный в основном где угодно выше определенного слоя; на данный момент, главным образом в моих ВОЙНАХ - Представление и Контроллер (в свободном смысле).

Править: Я должен действительно называть это Java EE, а не J2EE, не так ли?


Редактирование 2: Большое спасибо снова @Yishai для всей справки. После некоторых эмпирических, похоже, что я выяснил, как использовать единственный ClassLoder через ВОЙНЫ под JBoss 5. Я детализирую это ниже ради меня самого, и надо надеяться другие найдут это полезным также.

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

Вместо того, чтобы писать a jboss-web.xml для каждой ВОЙНЫ и a jboss.xml для EJB-JAR уха, помещенного a jboss-classloading.xml файл в каждой ВОЙНЕ, в том же месте как DD (web.xml). Содержание jboss-classloading.xml должен быть:




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

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

7
задан Arjan Tijms 24 March 2013 в 09:55
поделиться

5 ответов

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

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

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

Идея того, что объект хранит кешированное состояние само по себе, вполне нормальна, особенно с EJB3, где вы можете внедрить свое состояние вместо статической ссылки на него (если вы используете аннотацию @Service, тогда вам нужна специфическая для @Depends JBoss аннотация).При этом, если бы вы использовали здесь «правильный» синглтон, то я ожидал бы, что ваша единственная проблема с тем фактом, что ваши 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 . Он имеет ту же концепцию загрузчика-репозитория.

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

Это может немного прояснить ситуацию.

11
ответ дан 6 December 2019 в 15:19
поделиться

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

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

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

Но это просто сделать.

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

0
ответ дан 6 December 2019 в 15:19
поделиться

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

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

1
ответ дан 6 December 2019 в 15:19
поделиться

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

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

1
ответ дан 6 December 2019 в 15:19
поделиться

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

1
ответ дан 6 December 2019 в 15:19
поделиться
Другие вопросы по тегам:

Похожие вопросы: