由于问题范围很广,我会尽快回答并提供更多信息的链接。
根据 EJB 是否有状态,应用容器(在我的例子中是 GlassFish)对 EJB 施加了哪些不同的限制?
您的案例的主要区别在于以下规范的引用:
无状态会话 bean 是会话 bean,其实例没有
会话状态。这意味着所有 bean 实例都是
当他们不参与为客户调用提供服务时等效
方法。术语“无状态”表示实例没有状态
对于特定的客户。但是,实例的实例变量
可以包含跨客户端调用的方法调用的状态。示例
这种状态包括打开的数据库连接和对象引用
到企业 bean 对象。
在 @Stateful 的情况下,来自同一用户/客户端的客户端请求如何映射到正确的 bean(维护来自先前请求的客户端状态的 bean)?
在客户端,您必须存储对有状态会话 bean 的业务接口的引用。您从 EJB 容器中获得的这个对象。它是容器创建的对象,包含有关如何定位服务器端对象的详细信息。有关 GlassFish 中这些代理的一些信息可以从以下位置找到:
会话 bean 什么时候死掉?我假设它是在对 @Stateless 的请求完成后立即进行的,但对于 @Stateful 没有任何线索。
不,无状态会话 bean (SLSB) 在请求后不会死掉。无状态会话 bean 的生命周期是:
- 它是在容器决定时创建的。这自然发生在
在使用它之前的某个时间点,否则它在
容器。创建 SLSB 后,将其放入池中。
- 当某些客户端需要调用 SLSB 中的方法时,会在方法调用期间从池中取出一个实例。方法调用完成后,实例
返回到池中。然后这个实例(以及其他实例)就可以为下一个客户提供服务了。
- 当容器决定调整池大小时,SLSB 的生命周期结束
有状态会话 bean (SFSB) 的生命周期大致如下:
- 发生 JNDI 查找或注入时,容器会创建新实例。
- 在其生命周期内,SFSB 可以为多个方法调用提供服务。它也可以被钝化(基本上存储到磁盘以节省资源)并再次激活。
- 当调用 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;
}
}