【问题标题】:How GlassFish maps client requests to sessionsGlassFish 如何将客户端请求映射到会话
【发布时间】:2012-07-04 17:56:54
【问题描述】:

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

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

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

与此相切:

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

在此先感谢您的澄清。

【问题讨论】:

    标签: java jakarta-ee ejb-3.0 stateless-session-bean stateful-session-bean


    【解决方案1】:

    关于核心问题“我的 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 会话 - 它们根本不是一回事。

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

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

    【讨论】:

      【解决方案2】:

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

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

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

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

      【讨论】:

        【解决方案3】:
        • 如果在无状态会话 Bean 中有实例变量,它们的值将毫无意义(实际上)。这是因为您永远不知道将从实例池中检索无状态会话 Bean 的哪个实例来为请求提供服务。

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

        【讨论】:

          【解决方案4】:

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

          根据 EJB 是否有状态,应用容器(在我的例子中是 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 Tutorial 提供了比上面更详细的描述和图表。

          以及对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;
              }
          }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2018-04-24
            • 1970-01-01
            • 2022-10-13
            • 2014-05-19
            • 1970-01-01
            • 2020-09-20
            • 2010-11-27
            相关资源
            最近更新 更多