Sim, você pode misturar livremente CDI e EJB e obter ótimos resultados. Parece que você está usando @WebService
e @Schedule
, que são boas razões para adicionar EJB ao mix.
Há muita confusão por aí, então aqui estão algumas informações gerais sobre EJB e CDI, pois elas se relacionam entre si.
EJB> = CDI
Observe que os EJBs são beans CDI e, portanto, têm todos os benefícios do CDI. O inverso ainda não é verdadeiro. Portanto, definitivamente, não adquira o hábito de pensar "EJB vs CDI", pois essa lógica realmente se traduz em "EJB + CDI vs CDI", que é uma equação ímpar.
Nas versões futuras do Java EE, continuaremos alinhando-os. O que significa alinhar está permitindo que as pessoas façam o que eles já podem fazer, apenas sem o @Stateful
, @Stateless
ou @Singleton
anotação no topo.
EJB e CDI em termos de implementação
Por fim, o EJB e o CDI compartilham o mesmo design fundamental de serem componentes de proxy. Quando você obtém uma referência a um bean EJB ou CDI, não é o bean real. Em vez disso, o objeto que você recebe é falso (um proxy). Quando você invoca um método nesse objeto falso, a chamada vai para o contêiner que enviará a chamada por interceptadores, decoradores etc., além de cuidar de qualquer transação ou verificação de segurança. Feito tudo isso, a chamada finalmente vai para o objeto real e o resultado é passado de volta pelo proxy para o chamador.
A diferença ocorre apenas em como o objeto a ser chamado é resolvido. Por "resolvido", queremos dizer simplesmente onde e como o contêiner procura a instância real para invocar.
No CDI, o contêiner procura um "escopo", que basicamente será um hashmap que dura um período específico de tempo (por solicitação @RequestScoped
, por sessão HTTP @SessionScoped
, por aplicativo @ApplicationScoped
, conversação JSF @ConversationScoped
ou por sua implementação de escopo personalizado).
No EJB, o contêiner também pesquisará um hashmap se o bean for do tipo @Stateful
. Um @Stateful
bean também pode usar qualquer uma das anotações de escopo acima, fazendo com que ele viva e morra com todos os outros beans no escopo. No EJB @Stateful
é essencialmente o bean "qualquer escopo". O @Stateless
basicamente é um pool de instâncias - você obtém uma instância do pool pela duração de uma chamada. O @Singleton
é essencialmente@ApplicationScoped
Portanto, em um nível fundamental, qualquer coisa que você possa fazer com um bean "EJB", deverá poder fazer com um bean "CDI". Sob as cobertas, é muito difícil diferenciá-los. Todo o encanamento é o mesmo, com exceção de como as instâncias são resolvidas.
Atualmente, eles não são os mesmos em termos de serviços que o contêiner oferecerá ao fazer esse proxy, mas como eu disse, estamos trabalhando nele no nível de especificação do Java EE.
Nota de desempenho
Desconsidere qualquer imagem mental "leve" ou "pesada" que você possa ter. Isso é tudo de marketing. Eles têm o mesmo design interno para a maior parte. A resolução da instância CDI é talvez um pouco mais complexa porque é um pouco mais dinâmica e contextual. A resolução da instância EJB é relativamente estática, burra e simples em comparação.
Posso dizer a você, do ponto de vista da implementação no TomEE, que há uma diferença de desempenho zero entre invocar um EJB e invocar um CDI bean.
Padrão para POJOs, CDI e EJB
Obviamente, não use CDI ou EJB quando não houver benefício. Coloque o CDI quando começar a querer injeção, eventos, interceptadores, decoradores, rastreamento do ciclo de vida e coisas assim. Essa é a maior parte do tempo.
Além desses princípios, há uma série de serviços de contêiner úteis que você só tem a opção de usar se você fizer seu bean CDI também um EJB, adicionando @Stateful
, @Stateless
ou @Singleton
sobre ele.
Aqui está uma pequena lista de quando eu desmembrar os EJBs.
Usando JAX-WS
Expondo um JAX-WS @WebService
. Sou preguiçosa. Quando @WebService
também é um EJB, você não precisa listá-lo e mapeá-lo como um servlet no web.xml
arquivo. Isso é trabalho para mim. Além disso, tenho a opção de usar qualquer outra funcionalidade mencionada abaixo. Portanto, é um acéfalo para mim.
Disponível para @Stateless
e @Singleton
somente.
Usando JAX-RS
Expondo um recurso JAX-RS via @Path
. Eu ainda sou preguiçoso. Quando o serviço RESTful também é um EJB, você obtém novamente a descoberta automática e não precisa adicioná-lo a uma Application
subclasse JAX-RS ou algo assim. Além disso, posso expor exatamente o mesmo bean que um @WebService
se eu quiser ou usar qualquer uma das excelentes funcionalidades mencionadas abaixo.
Disponível para @Stateless
e @Singleton
somente.
Lógica de inicialização
Carregar na inicialização via @Startup
. Atualmente, não há equivalente a isso no CDI. De alguma forma, perdemos a adição de algo como um AfterStartup
evento no ciclo de vida do contêiner. Se tivéssemos feito isso, você simplesmente poderia ter um @ApplicationScoped
bean que o ouviu e que seria efetivamente o mesmo que um @Singleton
com @Startup
. Está na lista do CDI 1.1.
Disponível @Singleton
apenas para .
Trabalhando em Paralelo
@Asynchronous
invocação de método. Iniciar threads é um não-não em qualquer ambiente do lado do servidor. Ter muitos threads é um sério problema de desempenho. Essa anotação permite paralelizar as coisas que você faz usando o conjunto de encadeamentos do contêiner. Isso é incrível.
Disponível para @Stateful
, @Stateless
e @Singleton
.
Agendamento de trabalho
@Schedule
ou ScheduleExpression
é basicamente um cron ou Quartz
funcionalidade. Também é incrível. A maioria dos contêineres usa apenas quartzo sob as tampas para isso. A maioria das pessoas não sabe, no entanto, que o trabalho de agendamento no Java EE é transacional! Se você atualizar um banco de dados, agende algum trabalho e um deles falhará, ambos serão limpos automaticamente. Se a EntityManager
chamada persistir falhar ou houver um problema na liberação, não há necessidade de cancelar o agendamento do trabalho. Yay, transações.
Disponível para @Stateless
e @Singleton
somente.
Usando EntityManagers em uma transação JTA
A nota acima sobre transações, é claro, exige que você use um JTA
gerenciado EntityManager
. Você pode usá-los com "CDI" simples, mas sem as transações gerenciadas por contêiner, pode ser realmente monótono duplicar a UserTransaction
lógica de confirmação / reversão.
Disponível para todos os componentes Java EE, incluindo CDI, JSF @ManagedBean
, @WebServlet
, @WebListener
, @WebFilter
, etc. A @TransactionAttribute
anotação, no entanto, está disponível para @Stateful
, @Stateless
e @Singleton
única.
Mantendo o JTA gerenciado EntityManager
O EXTENDED
gerenciado EntityManager
permite manter uma EntityManager
abertura entre as JTA
transações e não perder os dados em cache. Bom recurso para a hora e o local certos. Use com responsabilidade :)
Disponível @Stateful
apenas para .
Fácil sincronização
Quando você precisa de sincronização, as anotações @Lock(READ)
e @Lock(WRITE)
são excelentes. Ele permite que você obtenha gerenciamento de acesso simultâneo gratuitamente. Ignore todo o encanamento ReentrantReadWriteLock. No mesmo depósito @AccessTimeout
, você pode dizer quanto tempo um encadeamento deve esperar para obter acesso à instância do bean antes de desistir.
Disponível @Singleton
apenas para beans.