【问题标题】:Passing state between EJB methods / @RequestScoped and @Stateless在 EJB 方法/@RequestScoped 和 @Stateless 之间传递状态
【发布时间】:2012-01-03 03:00:28
【问题描述】:

我有一个 @RequestScoped CDI bean,我想将其转换为 EJB 以获取声明性事务。 (我使用的是 EJB 3.1,Java EE 6)

目前,我在子例程之间传递状态,假设实例仅用于单个请求。如果我现在添加@Stateless,这个假设就会改变。

例如,我想做类似的事情

@Stateless
@Named
@RequestScoped
public class Foo {
  private String var1; // can't use instance vars in @Stateless?
  private String var2;

  public void transactionForRequest() {
    var1 = value; 
    var2 = value;
    ....
    subroutine();
  }
}

我认为上述方法不起作用-对吗?

我正在考虑两种选择:

  • 使用@Stateful 而不是@Stateless,以及@Named 和@RequestScoped。
  • 保留@Stateless 并使用EJBContext.getContextData 映射替换实例变量。

哪个更好?还有其他我没有想到的选择吗? (除了等待 Java EE 7 或切换到 Spring。:-))

【问题讨论】:

  • 使用@Stateful 可能是一种过度技能。您是否考虑过使用普通的无状态 bean 和 @ConversationScoped 托管 bean 来传递状态?
  • 这将如何工作 - 你会让 EJB @Stateless 然后 @Inject 成为 CDI bean 吗?这个 CDI bean 可以是 @RequestScoped 吗?
  • 我将 bean 保留为 @Stateless 并使用 @ConversationScoped bean 在页面之间传递变量。看看这个article关于创建向导。
  • 我不想进行类似向导的对话 - 我想在单个 HTTP 请求/数据库事务范围内的子例程之间传递变量。
  • 如果是这样,带有 Stateless bean 的 @SessionScoped bean 可能仍然比 Stateful bean 更容易管理。

标签: ejb java-ee-6 cdi ejb-3.1


【解决方案1】:

虽然@Stateless@Singleton@MessageDriven 可以通过@Inject 注入作用域引用,但它们不能成为@RequestScoped 或任何其他作用域。只有@Stateful 模型足够灵活以支持范围。换句话说,您可以将@Stateful bean 类本身注释为@RequestScoped@SessionScoped 等。

简单来说@Stateless@Singleton 已经固定了“范围”。 @Singleton 本质上是@ApplicationScoped@Stateless 可能是一些像@InvocationScoped 这样的虚构范围,如果存在的话。 @MessageDriven bean 的生命周期完全取决于驱动它的连接器,因此也不允许有用户定义的范围。

另见https://stackoverflow.com/a/8720148/190816

【讨论】:

  • 大卫,只是为了确定 - 如果我有 @RequestScoped 引用 @Stateless EJB - 它能给我带来什么?在整个请求过程中我会得到相同的引用,但它仍然(可能)是对代理的引用,所以每次我使用这个引用时,我都可以以不同的 EJB 实例结束。这是正确的吗?
  • 没错。从长远来看,在 OpenEJB 中,我们只为每个无状态 bean 创建一个代理并与整个应用程序共享。单身人士也一样。如果将 RequestScoped(或其他范围)放在无状态或单例上,则应将其视为部署错误。我必须仔细检查规范和 TCK,但这肯定是我这样做的方式。其他任何东西都只是误导。
  • 感谢大卫的澄清。这只是 EJB 和 CDI 之间的连接可能会迷失方向的又一次......
  • 之前没有想到这一点,但是将 Singleton 追溯声明为 Stereotype 的一种形式并使用 ApplicationScoped 对其进行注释可能会很有趣。可能更清楚一点,它实际上确实有一个范围,并且该范围不能更改。
  • 这听起来很合理。它不会破坏 EJB 规范并使 Singleton EJB 只是 CDI bean 的一个特例。我希望 EE 7 能重新组织这个东西。如果能够以这种方式将 SLSB 和 SFSB 映射到某些 CDI 刻板印象,那就太好了。那么 CDI 上下文将真正成为 EE 中每种类型 bean 的核心部分。
【解决方案2】:

我会选择 SFSB 而不是 SLSB。你想保持一个状态,所以对我来说这是最重要的信息——这是有状态 EJB 的工作。

我也不认为EJBContext#getContextData() 会帮助你。据我记得,它只在通话期间有效。因此,每次调用 EJB 上的方法都会创建新的上下文数据映射(至少这是我所期望的。)

【讨论】:

  • 很高兴听到@Stateful + @RequestScoped 会起作用 - 无论出于何种原因,“有状态会话 bean”仍然听起来像一个肮脏的词,但“请求范围的会话 bean”听起来要好得多。另外 - EJBContext#getContextData() 在这种情况下对我来说很好,因为子例程是本地方法调用 (this.subroutine()) 而不是 EJB 调用。
  • 你是对的 - 如果它的本地调用比上下文数据很好。我以为你确实注入了 EJB(@EJB@Inject)并在代理实例上调用了几个方法。
【解决方案3】:

如果您使用的是无状态 bean,那么您将负责任何状态管理,并且您通常会使用 HttpSessions 在 Web 应用层中执行此操作。是的,你不能使用实例变量,因为无状态 bean 是池化的。

【讨论】:

    猜你喜欢
    • 2013-12-31
    • 2012-02-01
    • 1970-01-01
    • 2021-05-02
    • 2017-10-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多