Да, вы можете свободно смешивать 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
события в жизненный цикл контейнера. Если бы мы сделали это, у вас просто мог бы быть @ApplicationScoped
bean-компонент, который его слушал, и это было бы фактически то же самое, что и @Singleton
with @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
только для фасоли.