由于问题范围很广,我将尝试尽快回答并提供更多信息的链接。
应用程序容器(在我的情况下为 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 教程中提供了比上面更详细的描述和图表。
以及对 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;
}
}