1

使用 EJB (3.x),您可以选择会话 Bean:@Stateful@Stateless. 如果我了解这两个选项背后的基础知识:

  • @Stateful- 每个用户/客户都有自己的,因此通常不会被汇集;跨多个请求维护状态
  • @Stateless- 不维护请求之间的状态,因此通常是池化的,因此每个新的客户端请求都会获得一个新的 bean

我的核心问题很简单,但是我有几个与之相关的小问题:我的 POJO 设计在@Statefulbeans 与. 之间有何不同@Stateless换句话说,如果我有一个HelloWorld实现Hello接口的 bean,那么 POJO 的设计如何根据我是否希望它是有状态的而改变?

与此相切:

  • 应用程序容器(在我的情况下为 GlassFish)对 EJB 施加了哪些不同的限制,具体取决于它是否有状态?
  • 在 的情况下@Stateful,来自同一用户/客户端的客户端请求如何映射到正确的 bean(从前一个请求维护客户端状态的 bean)?
  • 会话 bean 什么时候死?我假设它在请求完成后立即@Stateless,但没有任何线索@Stateful

在此先感谢您的澄清。

4

4 回答 4

2

关于核心问题“我的 POJO 设计在 @Stateful bean 与 @Stateless 之间有何不同”:

您的 hello world 示例是 @Stateless 会话 bean 的一个很好的示例:实现没有状态(没有类实例变量)。它不对状态做任何假设。如果您确实需要 @Stateless bean 中的“更多信息”,请查找、(重新)计算它等。如果您违反此规则并在 bean 上定义实例变量,则无法保证该信息将是您所期望的每次调用 bean 时都要这样做:不要这样做。

您对@Stateful bean 的设计将保留容器将在 bean 的生命周期内保留的内部状态(类实例变量);bean 必须是可序列化的。在会话的生命周期内保持 bean 存在相关的非常实际的运行时成本(内存和管理第二个切线问题的问题,特别是在集群环境中) - 所以只在适当的时候使用它(这证明了@Stateless bean 的存在)。

例如,考虑一个简单的注册页面:输入用户名、电子邮件地址等,然后输入“您确定”吗?@Stateful bean 可以保留此临时信息,直到您准备好将其提交到后端。

谷歌示例;这是一个:http ://docs.redhat.com/docs/en-US/JBoss_Enterprise_Application_Platform/6/html/Beta_Documentation/Stateful_Session_Bean_Example.html

客户端如何映射到正确的 @Stateful bean 是真正依赖于实现的(不是指定的),但是您可以期望它的管理类似于您的 Servlet 会话信息的维护方式。也就是说,不要将 Servlet 会话与 @Stateful 会话混淆——它们根本不是一回事。

对于您的@Stateful bean 中的Java EE 5/6,使用@Remove 注释一个方法,当您的客户端调用该方法时,它将被释放回以太。除此之外,只要您持有对@Stateful bean 的引用(即在您的Servlet 会话中),您就可以期望@Stateful bean 在您需要的时候出现。

另见:http ://docs.oracle.com/javaee/5/tutorial/doc/bnbmt.html

于 2012-07-06T20:24:58.430 回答
0
  • 如果您在无状态会话 Bean 中有实例变量,那么它们的值将毫无意义(实际上来说)。这是因为您永远不知道将从实例池中检索无状态会话 Bean 的哪个实例来为请求提供服务。

  • 无状态会话 Bean 仅在容器决定杀死它们时才会死亡。它们根据需要被实例化,并且只有在容器决定销毁它们时才会被销毁(例如,如果它决定使实例池更小)。您说您假设它们在请求后被销毁,但这是不正确的。在请求之后,它们将返回到实例池并保持准备好为下一个请求提供服务。

于 2012-07-06T20:00:32.557 回答
0

由于问题范围很广,我将尝试尽快回答并提供更多信息的链接。

应用程序容器(在我的情况下为 GlassFish)对 EJB 施加了哪些不同的限制,具体取决于它是否有状态?

您的案例的主要区别在于以下规范的引用:

无状态会话 bean 是其实例没有会话状态的会话 bean。这意味着,当所有 bean 实例不参与服务客户端调用的方法时,它们都是等效的。术语“无状态”表示实例没有特定客户端的状态。但是,实例的实例变量可以包含跨客户端调用的方法调用的状态。这种状态的示例包括打开的数据库连接和对企业 bean 对象的对象引用。

在@Stateful 的情况下,来自同一用户/客户端的客户端请求如何映射到正确的 bean(从前一个请求维护客户端状态的 bean)?

在客户端,您必须存储对有状态会话 bean 的业务接口的引用。您从 EJB 容器中获得的这个对象。它是容器创建的对象,包含有关如何定位服务器端对象的详细信息。有关 GlassFish 中这些代理的一些信息可以从以下位置找到:

会话 bean 什么时候死?我假设它在对@Stateless 的请求完成后立即进行,但对@Stateful 没有任何线索。

不,无状态会话 bean (SLSB) 在请求后不会死掉。无状态会话 bean 的生命周期是:

  1. 它是在容器决定时创建的。这在使用之前的某个时间点会自然发生,但除此之外它就在容器的手中。创建 SLSB 后,将其放入池中。
  2. 当某些客户端需要调用 SLSB 中的方法时,会在方法调用期间从池中取出一个实例。方法调用完成后,实例返回池中。然后这个实例(以及其他实例)准备好为下一个客户服务。
  3. 当容器决定调整池的大小时,SLSB 的生命周期结束

有状态会话 bean (SFSB) 的生命周期大致如下:

  1. 当 JNDI 查找或注入发生时,容器会创建新实例。
  2. 在其生命周期中,SFSB 可以为多个方法调用提供服务。它也可以被钝化(基本上存储到磁盘以节省资源)并再次激活。
  3. 当调用 remove 方法或发生超时(SFSB 在一段时间内未使用)时,SFSB 的生命周期结束。容器通常具有特定于实现的默认超时,并且超时也可以调整。在 Java EE 6 (EJB 3.1) 中,可以通过StatefulTimeout调整每个 bean 的超时时间。

此外,当系统异常发生时,会话 bean 的实例将被丢弃。系统异常是 RuntimeException(未标记为应用程序异常)或 java.rmi.RemoteException。SLSB 的实例被丢弃的事实对客户端是透明的。下一次调用肯定会由其他 SLSB 实例提供服务。在 SFSB 的情况下,未来所有可能的业务方法调用都将失败,因为 SFSB 的服务器端实例不再存在。详细信息可以在 EJB 3.1 规范第 14 章中找到。

可以从 EJB 3.1 规范 (4.6, 4.7) 中找到生命周期的明确而详细的描述。Java EE 6 教程中提供了比上面更详细的描述和图表。

以及对 Hello 服务设计的主要影响是什么:

@Stateless
public class HelloStateless implements HelloRemote {
    @Override
    public String getGreeting(String name) {
        return "Hi " + name;
    }
}


/**
 * This design is not possible for Stateless, because
 * subsequent calls to setName and getGreeting can be
 * handled by two different instances. For stateful it 
 * is fine, because we use one exclusively one instance.
 */
@Stateful
public class HelloStateful {

    private String name;
    public void setName(String name) {
        this.name = name;
    }

    public String getGreeting() {
        return "Hi " + name;
    }
}
于 2012-07-10T07:02:59.920 回答
0

1) 你的 EJB/Pojo 真的不知道区别。作为开发人员,您会这样做,但在代码级别,无状态 bean 看起来很像有状态 bean。生命周期和回调实际上是相同的,区别在于客户端可以更好地控制该生命周期,而对于无状态 bean,容器可以控制该生命周期。

2) 您的客户端只是维护 Session Bean 实例的副本。因此,例如,在 Web 容器中,您可以简单地将实例填充到会话中。您不想做的只是不断地为每个请求注入一个有状态会话 bean(使用@EJB),因为这每次都会创建一个新的。最好检查你的会话,如果它不存在,然后正常查找。

3) 有状态bean 可以有一个用@Remove 注释的方法。当您调用此方法时,bean 将被销毁。如果你不调用这个方法,容器有一个超时功能,它会在一些配置的持续时间后自动获取会话 bean。不期望有状态 bean 在服务器重新启动后仍然存在(尽管该合同在集群环境中可能会有所不同)。

还有一堆遗留的 EJB 2 行为大部分都可以工作,你只需要跳过障碍就可以得到它,现代的东西更容易。

于 2012-07-06T19:26:12.830 回答