5

我想我在这里有一个基本的理解问题,我希望有人可以向我解释。

假设我们有一个有状态的 EJB_A 和一个有状态的 EJB_B 和一个 sessionscoped ManagedbeanA:

@Stateful
@LocalBean
public class EJB_A {
}

@Stateful
@LocalBean
public class EJB_B {
  @EJB
  EJB_A ejb;
}
@ManagedBean
@SessionScoped
public class ManagedBeanA {
   @EJB
   EJB_A ejb;
}

在 ManagedBeanA 中,创建了 EJB_A。现在,当我使用具有 EJB_A 作为属性的 EJB_B 时,将在 EJB_B 中创建 EJB_A 的新实例。它与之前在 ManagedBeanA 中创建的 EJB_A 实例不同。

我不明白这一点,因为我认为有状态 EJB 的全部意义在于,对于每个客户端,只有一个实例由 EJB 容器创建、共享和管理。有人可以向我解释一下吗?还请解释我如何实现一个 EJB 的同一个实例由多个其他 EJB 共享?

谢谢

4

3 回答 3

9

是的,您混淆了不同的概念,以及不同的 API... 我宁愿使用 @Inject 而不是 @EJB 并指定注入实例的范围。

@Stateful
@LocalBean
public class EJB_A {
}

@Stateful
@LocalBean
public class EJB_B {
  @Inject @SessionScoped
  EJB_A ejb;
}
@ManagedBean
@SessionScoped
public class ManagedBeanA {
   @Inject @SessionScoped
   EJB_A ejb;
}
于 2012-11-30T09:34:42.373 回答
2

我只是在这里做了一些阅读。

原因是 EJB 3.0 有状态会话 bean 远程或本地业务接口的每个 lookup() 都会导致创建新的 bean 身份。从查找返回的每个引用都指向不同的有状态会话 bean。由调用者决定如何管理对该引用的访问。通常,Web 应用程序会将引用存储在 HttpSession 或应用程序范围 (ServletContext) 范围内以供后续访问。

和:

不要忘记在您的情况下,我们正在处理两种类型的会话:bean 会话和 Web 会话。前者确保一旦您请求有状态 bean,它的身份在该用户会话中保持不变。但是当您使用后者时,您在 bean 会话之上还有一个 Web 会话。为确保您从 2 个不同的 JSP(或在您进行重新加载时)访问同一个 bean,您需要将 bean 的标识存储到 Web 会话范围中。

所以你实际上是对的。当您想使用您的实例时,您必须使用 ManagedBean 在其他地方检索它,因为 EJB 实例与此会话上下文相关联。因此,如果您想简化它并确保每个会话只存在一次 EJB,请使用 CDI 并使用@javax.enterprise.context.SessionScoped;注释 EJB 本身。比你可以肯定的。

于 2012-11-30T09:26:54.743 回答
1

我想我混淆了两件事——@Sessionscoped 和@Stateful。

@Stateful 注解并不意味着每个客户端只创建一个实例。这只是意味着@Stateful-EJB 只属于一个客户端,而@Stateless-EJB 可以由多个客户端共享。

因此,@Stateful-EJB 具有 N:1 关系(N 个 @Stateful-EJB 恰好属于一个客户端),@Stateless-EJB 具有 N:M 关系(N 个 @Stateless-EJBS 属于 M 个客户端)。这意味着一个 EJB 实例不能被多个其他 EJB 共享,只需使用 @Stateful EJB 的 @EJB-Annotation。

另一方面,@Sessionscoped-Managedbean 似乎每个客户端只创建一次。

我做对了吗?

于 2012-11-30T08:44:05.217 回答