Где использовать EJB 3.1 и CDI?

120

Я делаю продукт на основе Java EE, в котором использую GlassFish 3 и EJB 3.1.

Мое приложение имеет сессионные компоненты , планировщик и использует веб-службы. Недавно я узнал об Apache TomEE , который поддерживает внедрение контекстов и зависимостей (CDI) . Контейнер GlassFish также поддерживает CDI.

Могу ли я заменить сессионные компоненты, если мне не нужны какие-либо функции, которые еще не предоставляет CDI? И если тогда, какие преимущества я могу получить?

Друмил Шах
источник

Ответы:

409

Да, вы можете свободно смешивать CDI и EJB и добиваться отличных результатов. Похоже, вы используете @WebServiceи @Schedule, и это веские причины для добавления EJB в микс.

Здесь много путаницы, поэтому вот некоторая общая информация о EJB и CDI, поскольку они связаны друг с другом.

EJB> = CDI

Обратите внимание, что EJB являются компонентами CDI и поэтому обладают всеми преимуществами CDI. Обратное неверно (пока). Так что определенно не входите в привычку думать «EJB против CDI», поскольку эта логика действительно переводится в «EJB + CDI против CDI», что является странным уравнением.

В будущих версиях Java EE мы продолжим их согласовывать. Выравнивание означает, что люди позволяют делать то, что они уже умеют, только без аннотации @Stateful, @Statelessили @Singletonвверху.

EJB и CDI в условиях реализации

В конечном счете, EJB и CDI используют один и тот же фундаментальный принцип работы прокси-компонентов. Когда вы получаете ссылку на EJB или CDI bean, это не настоящий bean. Скорее всего, вам дается подделка (прокси). Когда вы вызываете метод для этого поддельного объекта, вызов переходит к контейнеру, который отправит вызов через перехватчики, декораторы и т. Д., А также позаботится о любых транзакциях или проверках безопасности. Как только все это будет сделано, вызов, наконец, переходит к реальному объекту, а результат передается обратно через прокси вызывающему.

Разница только в том, как разрешается вызываемый объект. Под «разрешенным» мы просто подразумеваем, где и как контейнер ищет реальный экземпляр для вызова.

В CDI контейнер смотрит в «область действия», которая в основном будет хэш-картой, которая существует в течение определенного периода времени (для каждого запроса @RequestScoped, для каждого сеанса HTTP @SessionScoped, для каждого приложения @ApplicationScoped, диалога JSF @ConversationScopedили в соответствии с вашей реализацией настраиваемой области).

В EJB контейнер также просматривает хэш-карту, если bean-компонент имеет тип @Stateful. @StatefulКомпонент может также использовать любой из перечисленных выше области видимости аннотации , заставляя его жить и умереть со всеми другими компонентами в объеме. В EJB @Statefulпо сути является bean-компонент с любой областью действия. По @Statelessсути, это пул экземпляров - вы получаете экземпляр из пула на время одного вызова. По @Singletonсути@ApplicationScoped

Итак, на фундаментальном уровне все, что вы можете делать с компонентом «EJB», вы должны уметь делать с помощью компонента «CDI». Под одеялом их ужасно сложно отличить. Вся сантехника такая же, за исключением того, как разрешаются экземпляры.

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

Примечание производительности

Не обращайте внимания на любые «легкие» или «тяжелые» мысленные образы, которые могут у вас возникнуть. Это все маркетинг. У них по большей части одинаковая внутренняя конструкция. Разрешение экземпляра CDI, возможно, немного сложнее, потому что оно немного более динамично и контекстно. Разрешение экземпляра EJB довольно статично, глупо и просто по сравнению.

С точки зрения реализации в TomEE я могу сказать, что разница в производительности между вызовом EJB и вызовом CDI-компонента практически равна нулю.

По умолчанию для POJO, затем CDI, затем EJB

Конечно, не используйте CDI или EJB, если это не приносит пользы. Добавьте CDI, когда вам нужны инъекции, события, перехватчики, декораторы, отслеживание жизненного цикла и тому подобное. Это самое время.

Помимо этих основах, существует целый ряд полезных контейнерных услуг , которые вы только можете использовать , если вы сделаете свой CDI боб также EJB, добавив @Stateful, @Statelessили @Singletonна нем.

Вот краткий список того, когда я выделяю EJB.

Использование JAX-WS

Открытие JAX-WS @WebService. Мне лень. Когда @WebServiceэто также EJB, вам не нужно перечислять его и отображать как сервлет в web.xmlфайле. Для меня это работа. Кроме того, у меня есть возможность использовать любые другие функции, упомянутые ниже. Так что для меня это не проблема.

Доступно @Statelessи @Singletonтолько.

Использование JAX-RS

Предоставление ресурса JAX-RS через @Path. Я все еще ленив. Когда служба RESTful также является EJB, вы снова получаете автоматическое обнаружение, и вам не нужно добавлять его в Applicationподкласс JAX-RS или что-то подобное. Кроме того, я могу предоставить тот же компонент, что и объект, @WebServiceесли захочу, или использовать любую из замечательных функций, упомянутых ниже.

Доступно @Statelessи @Singletonтолько.

Логика запуска

Загружать при запуске через @Startup. В настоящее время в CDI нет эквивалента. Как-то упустили добавление чего-то вроде AfterStartupсобытия в жизненный цикл контейнера. Если бы мы сделали это, у вас просто мог бы быть @ApplicationScopedbean-компонент, который его слушал, и это было бы фактически то же самое, что и @Singletonwith @Startup. Это в списке для CDI 1.1.

Доступно @Singletonтолько для.

Параллельная работа

@Asynchronousвызов метода. Запустить потоки нельзя ни в одной серверной среде. Слишком много потоков - серьезный убийца производительности. Эта аннотация позволяет вам распараллеливать то, что вы делаете, используя пул потоков контейнера. Это круто.

Доступно для @Stateful, @Statelessи @Singleton.

Планирование работы

@Scheduleили ScheduleExpressionэто в основном cron или Quartzфункциональность. Также очень круто. В большинстве контейнеров для этого используется только кварц. Однако большинство людей не знают, что планирование работы в Java EE является транзакционным! Если вы обновляете базу данных, а затем планируете некоторую работу, и одна из них выходит из строя, обе будут автоматически очищены. Если EntityManagerпостоянный вызов завершился неудачно или возникла проблема с очисткой, нет необходимости отменять график работы. Ура, сделки.

Доступно @Statelessи @Singletonтолько.

Использование EntityManager в транзакции JTA

Приведенное выше примечание о транзакциях, конечно, требует, чтобы вы использовали JTAуправляемый EntityManager. Вы можете использовать их с обычным «CDI», но без транзакций, управляемых контейнером, это может стать действительно монотонным, дублируя UserTransactionлогику фиксации / отката.

Доступный для всех компонентов Java EE , включая CDI, JSF @ManagedBean, @WebServlet, @WebListener, @WebFilterи т.д. @TransactionAttributeаннотацию, однако, доступен @Stateful, @Statelessи @Singletonтолько.

Сохранение управления JTA EntityManager

EXTENDEDУдалось EntityManagerпозволяет держать EntityManagerоткрытыми между JTAсделками и не теряйте кэшированных данных. Хорошая функция для подходящего времени и места. Используйте ответственно :)

Доступно @Statefulтолько для.

Легкая синхронизация

При необходимости синхронизации, то @Lock(READ)и @Lock(WRITE)аннотации довольно отлично. Это позволяет вам получить управление одновременным доступом бесплатно. Пропустите всю сантехнику ReentrantReadWriteLock. В том же ведре находится @AccessTimeout, что позволяет вам сказать, как долго поток должен ждать, чтобы получить доступ к экземпляру компонента, прежде чем отказаться.

Доступно @Singletonтолько для фасоли.

Дэвид Блевинс
источник
32
Боже мой, Дэвид :) Думаю, ты это прикрыл.
LightGuard
7
Спасибо за этот ответ. Вы прочистили засор в моей голове и соединили много точек.
Thupten
7
Это, безусловно, лучшее объяснение по этой теме, которое я когда-либо читал. Он также охватывает почти все важные аспекты использования EJB в реальной жизни. Отличная работа!!
nanoquack
3
Это очень понятно, и Адам не ошибается в строгих юридических терминах, но различие спорный. В спецификации говорится, что экземпляр EJB не является контекстным, но позже говорится, что ссылка (прокси) на EJB является контекстной. Жизненный цикл bean-компонента с отслеживанием состояния полностью контролируется через ссылку (прокси), поэтому, когда контейнер CDI управляет этой ссылкой (прокси), математические вычисления выполняются одинаково - EJB с отслеживанием состояния могут эффективно быть контекстными.
Дэвид Блевинс
4
Это ответ 2012 года, есть ли у нас последние обновления?
Аббас
2

Если вы действительно не используете ни одну из функций ejb 3.1, ответ прост. но угадайте, что ваш вопрос указывает на то, что вы подозреваете, что существуют концепции ejb 3.1, которыми вы пользуетесь, не зная о них. одним из примеров может быть то, что контейнер может держать пул slsb готовым к использованию, так что jms и соединения с базой данных не нужно вводить как часть запроса

Аксель Вилльгерт
источник