【问题标题】:JEE7: Do EJB and CDI beans support container-managed transactions?JEE7:EJB 和 CDI bean 是否支持容器管理的事务?
【发布时间】:2013-07-24 04:15:35
【问题描述】:

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 - 它没有类级别的注释),基于thissn-p:

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 类型实际上支持容器管理的事务?
  • 只是为了好奇,如果上面的代码有误,我怎么能用一个简单的演示应用程序来测试它?

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

【问题讨论】:

  • “为了摆脱我心中的混乱”,如此真实

标签: java jakarta-ee ejb cdi jta


【解决方案1】:

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

【讨论】:

  • 哦,现在我明白了。实际上,我确实混淆了 EJB 规范中的 javax.ejb.TransactionAttribute(它是 JEE5+ 的一部分)和 javax.transaction.Transactional(它添加到新的 JTA 1.2 规范中,现在是 JEE7 的一部分)。所以,这是个好消息!如果我没听错的话,这可能会扼杀中型应用程序的 EJB 层。
  • 另一个旁注:同时拥有来自 JTA 和 EJB 规范的事务属性只是 JEE 生态系统中另一个令人困惑的 DRY 违规,对吗? javax.ejb.TransactionAttribute 现在是否可以被视为已弃用,即使对于 EJB 也是如此?
  • 否,因为默认情况下 EJB 是事务性的(约定优于配置方法),因此您获得特定注释是正常的。另外,您可以使用 EJB 执行高级事务,例如嵌套事务或管理 XA 事务。但是请记住,当您需要 EJB 时,它可以(并且应该)始终是 CDI bean。是的,CDI 可以替代 EJB 用于轻量级应用程序。
  • 我明白了。但是在我看来,他们应该将所有事务都集中在 JTA 规范中,而不是更多特定于 EJB 的事务处理。但是,让我们在这里停止讨论。感谢您的澄清。
  • 我会说使用@Inject 如果你想让容器自动处理“正常范围”的生命周期(除了@Dependent@Stateful EJB 并让容器为您传递有状态引用。否则,您最终可能会遇到非法组合范围(CDI 1.1,第 3.2 节)或尝试查找 @Remote EJB,如果没有上面答案中发布的臃肿黑客,它将失败。寻找 EJB?使用@EJB。使用 @Inject 仅对声明 CDI 范围的 @Stateful 有意义。
【解决方案2】:

javadoc of Transactional 说:

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-19
    • 1970-01-01
    相关资源
    最近更新 更多