Где использовать EJB 3.1 и CDI?
Я делаю продукт на основе Java EE, в котором я использую GlassFish 3 и EJB 3.1.
Мое приложение имеет сессионные компоненты, планировщик и использует веб-сервисы. Недавно я узнал об Apache TomEE, который поддерживает контексты и внедрение зависимостей (CDI). Контейнер GlassFish также поддерживает CDI.
Могу ли я заменить сессионные компоненты, если мне не требуется какая-либо функция, которую CDI также не предоставляет? И если тогда, какие преимущества я могу получить?
3 ответа
Да, вы можете свободно смешивать как 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, это не настоящий бин. Скорее объект, который вам дают, является подделкой (прокси). Когда вы вызываете метод для этого поддельного объекта, вызов переходит к контейнеру, который отправит вызов через перехватчики, декораторы и т. Д., А также позаботится о любых транзакциях или проверках безопасности. Как только все это сделано, вызов, наконец, переходит к реальному объекту, а результат передается обратно через прокси вызывающей стороне.
Разница только в том, как разрешается вызываемый объект. Под "разрешенным" мы просто подразумеваем, где и как контейнер ищет реальный экземпляр для вызова.
В CDI контейнер выглядит в "области видимости", которая в основном будет хеш-картой, которая живет в течение определенного периода времени (на запрос @RequestScoped
за сеанс HTTP @SessionScoped
за приложение @ApplicationScoped
JSF Conversation @ConversationScoped
или согласно вашей индивидуальной реализации объема).
В EJB контейнер также смотрит на hashmap, если бин имеет тип @Stateful
, @Stateful
bean-компонент также может использовать любые из приведенных выше аннотаций области действия, заставляя его жить и умирать со всеми другими компонентами в области действия. В EJB @Stateful
по сути, это бин "любой области". @Stateless
в основном это пул экземпляров - вы получаете экземпляр из пула на время одного вызова. @Singleton
по существу @ApplicationScoped
Итак, на фундаментальном уровне все, что вы можете сделать с EJB-компонентом, вы должны уметь делать с CDI-компонентом. Под покровами очень сложно отличить их друг от друга. Вся сантехника одинакова за исключением того, как решаются случаи.
В настоящее время они не одинаковы с точки зрения сервисов, которые контейнер будет предлагать при выполнении этого прокси, но, как я уже сказал, мы работаем над этим на уровне спецификации Java EE.
Примечание о производительности
Не обращайте внимания на любые "легкие" или "тяжелые" мысленные образы, которые у вас могут быть. Это все маркетинг. Они имеют одинаковый внутренний дизайн по большей части. Разрешение экземпляра CDI, возможно, немного сложнее, потому что оно немного более динамично и контекстуально. Разрешение экземпляра EJB довольно статично, тупо и просто в сравнении.
С точки зрения реализации в TomEE я могу сказать, что разница между вызовом EJB и вызовом компонента EJB практически нулевая.
По умолчанию для 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, вы снова получаете автоматическое обнаружение и вам не нужно добавлять его в JAX-RS Application
подкласс или что-нибудь подобное. Плюс я могу выставить точно такой же боб, как @WebService
если я хочу или использовать любой из замечательных функций, упомянутых ниже.
Доступен @Stateless
а также @Singleton
только.
Логика запуска
Загрузить при запуске через @Startup
, В настоящее время нет эквивалента этому в CDI. Почему-то мы пропустили добавление чего-то вроде AfterStartup
событие в жизненном цикле контейнера. Если бы мы сделали это, вы просто могли бы иметь @ApplicationScoped
боб, который слушал его, и это было бы фактически так же, как @Singleton
с @Startup
, Это в списке для CDI 1.1.
Доступен @Singleton
только.
Работая параллельно
@Asynchronous
вызов метода. Запустить потоки нет-нет в любой серверной среде. Наличие слишком большого количества потоков является серьезным фактором снижения производительности. Эта аннотация позволяет вам распараллеливать то, что вы делаете, используя пул потоков контейнера. Это круто.
Доступен @Stateful
, @Stateless
а также @Singleton
,
Планирование работы
@Schedule
или же ScheduleExpression
в основном крон или 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
только бобы.
Если вы действительно не используете какие-либо функции ejb 3.1, ответ прост. но угадайте, что ваш вопрос указывает на то, что вы подозреваете, что существуют ejb 3.1, которые вы получаете, даже не подозревая о них. Одним из примеров может быть то, что контейнер может держать пул slsb готовым к использованию, так что соединения jms и базы данных не нужно вводить как часть запроса.
Спасибо за это всеобъемлющее понимание. Но я часто задаюсь вопросом: когда необходимы сеансовые компоненты без сохранения состояния, которые извлекаются из пула, а не просто использование существующего CDI-компонента области приложения, который запрещает доступ нескольким потокам также без сохранения состояния?