20

Java EE7 由一堆“bean”定义组成:

  • 托管 Bean 1.0 (JSR-316 / JSR-250)
  • Java 1.0 (JSR-330) 的依赖注入
  • CDI 1.1 (JSR-346)
  • JSF 托管 Bean 2.2 (JSR-344)
  • EJB 3.2 (JSR-345)

为了摆脱脑海中的混乱,我研究了几篇“何时使用哪种bean类型”的文章。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 类型实际上支持容器管理的事务?
  • 只是为了好奇,如果上面的代码有误,我怎么能用一个简单的演示应用程序来测试它呢?

(顺便说一句:有人在这里描述了类似的问题,但它的解决方案不适用于我的情况。

4

2 回答 2

33

在 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。

于 2013-07-24T19:09:14.953 回答
7

Transactional的javadoc说:

javax.transaction.Transactional 注释使应用程序能够在类和方法级别上以声明方式控制 CDI 托管 bean 以及由 Java EE 规范定义为托管 bean 的类的事务边界,其中方法级别注释覆盖那些班级水平。

所以,你的假设是错误的。在 Java EE 6 之前,EJB 是唯一一种支持声明式事务的组件。Java EE 7 中准确地引入了事务注释,以使非 EJB 托管 CDI bean 事务化。

于 2013-07-24T17:25:10.037 回答