JEE7:EJB和CDI bean是否支持容器管理的事务?
Java EE7由一堆“bean”定义组成:
- Managed Beans 1.0(JSR-316 / JSR-250)
- Java 1.0的dependency injection(JSR-330)
- CDI 1.1(JSR-346)
- JSF Managed Beans 2.2(JSR-344)
- EJB 3.2(JSR-345)
为了摆脱我心中的混乱,我研究了几篇“何时使用哪种豆类”的文章。 EJB的一个优点似乎是它们单独支持声明式容器管理事务 (着名的事务注释)。 不过,我不确定这是否正确。 任何人都可以批准这个吗?
同时,我想出了一个简单的演示应用程序来检查这是否真的如此。 我刚刚根据这个片段定义了一个CDI bean( 不是 EJB – 它没有类级别注释),如下所示:
public class CdiBean { @Resource TransactionSynchronizationRegistry tsr; @Transactional(Transactional.TxType.REQUIRED) public boolean isTransactional() { return tsr.getTransactionStatus() == Status.STATUS_ACTIVE; } }
现在,GlassFish 4.0的结果是这个方法实际上返回true,根据我的询问,它没有按预期工作 。 我确实希望容器忽略CDI bean方法上的@Transactional注释,或甚至抛出exception。 我使用新安装的GlassFish 4服务器,因此没有干扰。
所以我的问题是:
- 哪些bean类型确实支持容器管理的事务?
- 只是为了好奇,如果上面的代码错误,我怎么能用一个简单的演示应用程序来测试呢?
(顺便说一句:有人在这里描述了类似的问题,但其解决方案并不适用于我的情况。
在Java EE 7之前,只有EJB是事务性的,并且@Transactional
注释不存在。
从Java EE 7和JTA 1.2开始,您可以在CDI中使用事务拦截器和@Transactional
注释。
要回答有关要使用的最佳bean类型的问题,默认情况下答案是CDI。
CDI bean比EJB轻,并且支持许多function(包括作为EJB),默认情况下会激活(当您将beans.xml
文件添加到应用程序时)。 由于Java EE 6 @Inject
取代了@EJB
。 即使您使用远程EJB(CDI中不存在的function),最佳做法是建议您@EJB
注入远程EJB和CDI生成器以将其公开为CDI bean
public class Resources { @EJB @Produces MyRemoteEJB ejb; }
对于Java EE资源也建议使用相同的方法
public class Resources2 { @PersistenceContext @Produces EntityManager em; }
这些生产者将在以后使用
public class MyBean { @Inject MyRemoteEJB bean; @Inject EntityManager em; }
EJB继续对它们包含的某些服务(如JMS或异步处理)有意义,但您将它们用作CDI bean。
Transactional的javadoc说:
javax.transaction.Transactional注释使应用程序能够以声明方式控制CDI托管bean上的事务边界,以及Java EE规范定义为托管bean的类,在类和方法级别,方法级别注释覆盖了class级。
所以,你的假设是错误的。 直到Java EE 6,EJB才是支持声明式事务的唯一组件。 事务性注释已经在Java EE 7中引入,以使非EJB,托管CDI bean具有事务性。