Java EE7由一堆"bean"定义组成:
- 托管 Bean 1.0 (JSR-316/JSR-250(
- Dependency Injection for Java 1.0 (JSR-330(
- CDI 1.1 (JSR-346(
- JSF Managed Bean 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注释,甚至抛出异常。我使用的是新安装的 GlassFish 4 服务器,因此没有干扰。
所以我的问题真的是:
- 哪些 Bean 类型实际上支持容器管理的事务?
- 只是出于好奇,如果上面的代码是错误的,我该如何用一个简单的演示应用程序来测试它?
(顺便说一句:有人在这里描述了类似的问题,但它的解决方案不适用于我的情况。
在Java EE 7之前,只有EJB是事务性的,@Transactional
注
从 Java EE 7 和 JTA 1.2 开始,您可以在 CDI 中使用带有@Transactional
注释的事务拦截器。
要回答您关于使用最佳 Bean 类型的问题,答案默认为 CDI。
CDI Bean 比 EJB 轻,支持许多功能(包括成为 EJB(,并且默认情况下处于激活状态(当您将beans.xml
文件添加到应用程序时(。由于Java EE 6 @Inject
取代@EJB
。即使您使用远程 EJB(CDI 中不存在的功能(,最佳实践也建议您@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 的类上的事务边界,其中方法级别注释覆盖了类级别的注释。
所以,你的假设是错误的。在Java EE 6之前,EJB是唯一支持声明式事务的组件。事务性注解正是在 Java EE 7 中引入的,以使非 EJB 托管的 CDI Bean 成为事务性。