JEE7:EJB 和 CDI Bean 是否支持容器管理的事务?

2022-09-02 09:11:13

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

  • 管理式 Bean 1.0 (JSR-316 / JSR-250)
  • 依赖注入 Java 1.0 (JSR-330)
  • CDI 1.1 (JSR-346)
  • JSF 管理豆 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 类型实际上支持容器管理的事务?
  • 只是为了好奇,如果上面的代码是错误的,我怎么能用一个简单的演示应用程序来测试它呢?

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


答案 1

在Java EE 7之前,只有EJB是事务性的,注释不存在。@Transactional

从 Java EE 7 和 JTA 1.2 开始,您可以在 CDI 中使用带有注释的事务拦截器。@Transactional

要回答有关要使用的最佳Bean类型的问题,默认情况下,答案是CDI。

CDI bean 比 EJB 轻,支持许多功能(包括作为 EJB),并且默认情况下处于激活状态(当您将文件添加到应用程序时)。自 Java EE 6 取代 .即使您使用远程 EJB(CDI 中不存在的功能),最佳实践也建议您一次性注入远程 EJB,并使用 CDI 创建器将其公开为 CDI Beanbeans.xml@Inject@EJB@EJB

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。


答案 2

Transactional 的 javadoc 说:

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

所以,你的假设是错误的。在 Java EE 6 之前,EJB 是唯一支持声明性事务的组件。事务性注释正是在 Java EE 7 中引入的,目的是使非 EJB、托管的 CDI bean 成为事务性的。


推荐