¿Dónde usar EJB 3.1 y CDI?

120

Estoy creando un producto basado en Java EE en el que estoy usando GlassFish 3 y EJB 3.1.

Mi aplicación tiene beans de sesión , un planificador y utiliza servicios web. Recientemente me enteré de Apache TomEE , que admite Contexts and Dependency Injection (CDI) . El contenedor GlassFish también admite CDI.

¿Puedo reemplazar los beans de sesión cuando no requiera ninguna función que CDI tampoco proporcione? Y si luego, ¿cuáles son los beneficios que puedo obtener?

Dhrumil Shah
fuente

Respuestas:

408

Sí, puede mezclar libremente CDI y EJB y lograr excelentes resultados. Parece que está usando @WebServicey @Schedule, que son buenas razones para agregar EJB a la mezcla.

Existe mucha confusión, por lo que aquí hay información general sobre EJB y CDI, ya que se relacionan con cada uno.

EJB> = CDI

Tenga en cuenta que los EJB son beans CDI y, por lo tanto, tienen todos los beneficios de CDI. Lo contrario no es cierto (todavía). Así que definitivamente no se acostumbre a pensar "EJB vs CDI", ya que esa lógica realmente se traduce en "EJB + CDI vs CDI", que es una ecuación extraña.

En futuras versiones de Java EE, continuaremos alineándolos. ¿Qué significa la alineación está permitiendo a la gente a hacer lo que ya pueden hacer, sólo que sin el @Stateful, @Statelesso @Singletonla anotación en la parte superior.

EJB y CDI en términos de implementación

En última instancia, EJB y CDI comparten el mismo diseño fundamental de ser componentes proxy. Cuando obtiene una referencia a un bean EJB o CDI, no es el bean real. Más bien, el objeto que se le da es falso (un proxy). Cuando invoca un método en este objeto falso, la llamada va al contenedor que enviará la llamada a través de interceptores, decoradores, etc., así como también se encargará de cualquier transacción o control de seguridad. Una vez hecho todo esto, la llamada finalmente va al objeto real y el resultado se devuelve a través del proxy a la persona que llama.

La diferencia solo radica en cómo se resuelve el objeto a invocar. Por "resuelto" simplemente queremos decir dónde y cómo el contenedor busca la instancia real para invocar.

En CDI, el contenedor se ve en un "alcance", que básicamente será un mapa de hash que vive durante un período de tiempo específico (por solicitud @RequestScoped, por sesión HTTP @SessionScoped, por aplicación @ApplicationScoped, conversación JSF @ConversationScopedo por su implementación de alcance personalizado).

En EJB, el contenedor también busca en un mapa hash si el bean es de tipo @Stateful. Un @Statefulbean también puede usar cualquiera de las anotaciones de alcance anteriores, lo que hace que viva y muera con todos los demás beans del alcance. En EJB @Statefules esencialmente el bean "cualquier ámbito". El @Statelesses básicamente una piscina ejemplo - se obtiene una instancia de la piscina durante la duración de una invocación. El @Singletones esencialmente@ApplicationScoped

Entonces, en un nivel fundamental, cualquier cosa que pueda hacer con un bean "EJB" debería poder hacer con un bean "CDI". Debajo de las sábanas es muy difícil distinguirlos. Toda la plomería es la misma con la excepción de cómo se resuelven las instancias.

Actualmente no son los mismos en términos de los servicios que el contenedor ofrecerá al hacer este proxy, pero como digo, estamos trabajando en el nivel de especificación de Java EE.

Nota de rendimiento

Haga caso omiso de las imágenes mentales "ligeras" o "pesadas" que pueda tener. Eso es todo marketing. Tienen el mismo diseño interno en su mayor parte. La resolución de la instancia CDI es quizás un poco más compleja porque es un poco más dinámica y contextual. La resolución de la instancia de EJB es bastante estática, tonta y simple en comparación.

Puedo decirle, desde una perspectiva de implementación en TomEE, que hay una diferencia de rendimiento nula entre invocar un EJB o invocar un bean CDI.

Por defecto a POJO, luego CDI, luego EJB

Por supuesto, no use CDI o EJB cuando no haya ningún beneficio. Agregue CDI cuando comience a querer inyección, eventos, interceptores, decoradores, seguimiento del ciclo de vida y cosas por el estilo. Esa es la mayor parte del tiempo.

Más allá de los conceptos básicos, hay una serie de servicios de contenedores útiles sólo tiene la opción de usar si usted hace su grano de CDI también un EJB mediante la adición de @Stateful, @Statelesso @Singletonen él.

Aquí hay una breve lista de cuándo analizo los EJB.

Usando JAX-WS

Exponiendo un JAX-WS @WebService. Soy perezoso. Cuando @WebServicetambién es un EJB, no es necesario enumerarlo y asignarlo como servlet en el web.xmlarchivo. Eso es trabajo para mí. Además, tengo la opción de usar cualquiera de las otras funciones que se mencionan a continuación. Así que es una obviedad para mí.

Disponible para @Statelessy @Singletonsolo.

Usando JAX-RS

Exponer un recurso JAX-RS a través de @Path. Todavía soy vago. Cuando el servicio RESTful también es un EJB, nuevamente obtiene el descubrimiento automático y no tiene que agregarlo a una Applicationsubclase JAX-RS ni nada de eso. Además, puedo exponer exactamente el mismo bean que un @WebServicesi quiero o usar cualquiera de las excelentes funciones que se mencionan a continuación.

Disponible para @Statelessy @Singletonsolo.

Lógica de inicio

Cargar al inicio a través de @Startup. Actualmente no existe un equivalente a esto en CDI. De alguna manera nos perdimos agregar algo como un AfterStartupevento en el ciclo de vida del contenedor. Si hubiéramos hecho esto, simplemente podría haber tenido un @ApplicationScopedbean que lo escuchara y eso sería efectivamente lo mismo que un @Singletonwith @Startup. Está en la lista de CDI 1.1.

Disponible @Singletonsolo para .

Trabajando en Paralelo

@Asynchronousinvocación del método. Iniciar subprocesos es un no-no en cualquier entorno del lado del servidor. Tener demasiados subprocesos es un serio asesino del rendimiento. Esta anotación le permite paralelizar las cosas que hace utilizando el grupo de subprocesos del contenedor. Esto es asombroso.

Disponible a @Stateful, @Statelessy @Singleton.

Programación del trabajo

@Scheduleo ScheduleExpressiones básicamente un cron o una Quartzfuncionalidad. También muy impresionante. La mayoría de los contenedores solo usan Quartz debajo de las cubiertas para esto. Sin embargo, la mayoría de la gente no sabe que programar el trabajo en Java EE es transaccional. Si actualiza una base de datos, luego programa algún trabajo y uno de ellos falla, ambos se limpiarán automáticamente. Si la EntityManagerllamada persistente falla o hay un problema de descarga, no es necesario cancelar la programación del trabajo. Bien, transacciones.

Disponible para @Statelessy @Singletonsolo.

Usando EntityManagers en una transacción JTA

La nota anterior sobre transacciones, por supuesto, requiere que utilice un JTAarchivo EntityManager. Puede usarlos con "CDI" simple, pero sin las transacciones administradas por el contenedor puede volverse realmente monótono duplicar la UserTransactionlógica de compromiso / retroceso.

Disponible para todos los componentes de Java EE incluyendo CDI, JSF @ManagedBean, @WebServlet, @WebListener, @WebFilter, etc. La @TransactionAttributeanotación, sin embargo, está disponible para @Stateful, @Statelessy @Singletonsolamente.

Mantener JTA administrado EntityManager

El EXTENDEDadministrado le EntityManagerpermite mantener una EntityManagerapertura entre JTAtransacciones y no perder los datos almacenados en caché. Buena característica para el momento y el lugar adecuados. Utilice responsablemente :)

Disponible @Statefulsolo para .

Fácil sincronización

Cuando necesita sincronización, las anotaciones @Lock(READ)y @Lock(WRITE)son bastante excelentes. Le permite obtener una gestión de acceso concurrente de forma gratuita. Omita todas las tuberías ReentrantReadWriteLock. En el mismo depósito está @AccessTimeout, lo que le permite decir cuánto tiempo debe esperar un hilo para obtener acceso a la instancia del bean antes de darse por vencido.

Disponible @Singletonsolo para frijoles.

David Blevins
fuente
32
Santo cielo David :) Creo que lo cubriste.
LightGuard
7
Gracias por esta respuesta. Ha limpiado la obstrucción en mi cabeza y ha conectado muchos puntos.
Thupten
7
Esta es, con mucho, la mejor explicación sobre ese tema que he leído. También cubre casi todos los aspectos importantes de EJB en el uso real. ¡¡Buen trabajo!!
nanoquack
3
Muy comprensible y Adam no se equivoca en términos estrictamente legales, pero la distinción es discutible. La especificación dice que la instancia de EJB no es contextual, pero luego dice que la referencia (proxy) a EJB es contextual. El ciclo de vida de un bean con estado se controla completamente a través de la referencia (proxy), por lo que cuando el contenedor CDI controla esa referencia (proxy), las matemáticas son iguales: los EJB con estado pueden ser contextuales de manera efectiva.
David Blevins
3
¿Escribiste esto en tu pausa para el almuerzo en TESLA?
Edison
2

si realmente no está utilizando ninguna de las características de ejb 3.1, la respuesta es simple. pero suponga que su pregunta indica que sospecha que hay conceptos ejb 3.1 de los que se está beneficiando sin ser consciente de ellos. un ejemplo podría ser que el contenedor puede mantener un grupo de slsb listo para ser utilizado, de modo que las conexiones de base de datos y jms no tengan que inyectarse como parte de la solicitud

Aksel Willgert
fuente