JEE7: ¿Los beans EJB y CDI admiten transacciones manejadas por contenedor?

Java EE7 consiste en un conjunto de definiciones de “bean”:

  • Managed Beans 1.0 (JSR-316 / JSR-250)
  • Inyección de Dependencia para Java 1.0 (JSR-330)
  • CDI 1.1 (JSR-346)
  • JSF Managed Beans 2.2 (JSR-344)
  • EJB 3.2 (JSR-345)

Para poder deshacerme del caos en mi mente, estudio varios artículos sobre “cuándo usar qué tipo de frijol”. Uno de los pros de EJB parece ser que solo soportan transacciones declarativas manejadas por contenedor (las famosas anotaciones de transacciones). No estoy seguro, sin embargo, si esto es correcto. ¿Alguien puede aprobar esto?

Mientras tanto, se me ocurrió una aplicación de demostración simple para comprobar si esto era cierto. Acabo de definir un bean CDI ( no un EJB, no tiene anotaciones de nivel de clase) de la siguiente manera, basado en este fragmento:

public class CdiBean { @Resource TransactionSynchronizationRegistry tsr; @Transactional(Transactional.TxType.REQUIRED) public boolean isTransactional() { return tsr.getTransactionStatus() == Status.STATUS_ACTIVE; } } 

Ahora, el resultado en GlassFish 4.0 es que este método realmente devuelve verdadero, lo cual, según mis investigaciones, no está funcionando como se esperaba . Esperaba que el contenedor ignorara la anotación @Transactional en un método de bean CDI, o incluso arrojara una excepción. Utilizo un servidor GlassFish 4 recién instalado, por lo que no hay interferencias.

Entonces mi pregunta es realmente:

  • ¿Qué tipos de frijoles realmente admiten transacciones manejadas por contenedores?
  • Solo por el bien de la curiosidad, ¿cómo podría probarlo con una simple aplicación de demostración si el código anterior es incorrecto?

(Por cierto: alguien describió un problema similar aquí , pero su solución no se aplica a mi caso.

Hasta Java EE 7, solo EJB era transaccional y la anotación @Transactional no existía.

Desde Java EE 7 y JTA 1.2 puede usar el interceptor transaccional en CDI con la anotación @Transactional .

Para responder a su pregunta sobre el mejor tipo de frijol a usar, la respuesta es CDI por defecto.

Los beans CDI son más livianos que EJB y admiten muchas características (incluido el ser EJB) y se activan de manera predeterminada (cuando agrega el archivo beans.xml a su aplicación). Desde Java EE 6 @Inject reemplaza @EJB . Incluso si utiliza EJB remotos (característica que no existe en CDI), la mejor práctica sugiere que @EJB una vez para inyectar EJB remoto y un productor de CDI para exponerlo como un frijol CDI

 public class Resources { @EJB @Produces MyRemoteEJB ejb; } 

Lo mismo se sugiere para los recursos de Java EE

 public class Resources2 { @PersistenceContext @Produces EntityManager em; } 

Estos productores serán utilizados más tarde

 public class MyBean { @Inject MyRemoteEJB bean; @Inject EntityManager em; } 

EJB sigue teniendo sentido para ciertos servicios que incluyen, como JMS o tratamiento asíncrono, pero los usará como CDI Bean.

El javadoc de Transactional dice:

La anotación javax.transaction.Transactional proporciona a la aplicación la capacidad de controlar declarativamente los límites de transacción en beans administrados CDI, así como las clases definidas como beans administrados por la especificación Java EE, en el nivel de clase y método donde las anotaciones de nivel de método anulan las de el nivel de clase.

Entonces, tus suposiciones son incorrectas. Los EJB, hasta Java EE 6, eran los únicos tipos de componentes para admitir transacciones declarativas. La anotación transaccional se ha introducido precisamente en Java EE 7 para hacer que los beans CDI gestionados no EJB sean transaccionales.