无状态和有状态企业 Java Bean

我正在学习Java EE 6教程,我试图理解无状态和有状态会话bean之间的区别。如果无状态会话 Bean 在方法调用之间不保留其状态,为什么我的程序会以这种方式运行?

package mybeans;

import javax.ejb.LocalBean;
import javax.ejb.Stateless;

@LocalBean
@Stateless
public class MyBean {

    private int number = 0;

    public int getNumber() {
        return number;
    }

    public void increment() {
        this.number++;
    }
}

客户

import java.io.IOException;
import javax.ejb.EJB;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.WebServlet;
import mybeans.MyBean;
import java.io.PrintWriter;

@WebServlet(name = "ServletClient", urlPatterns = { "/ServletClient" })
public class ServletClient extends HttpServlet {
    private static final long serialVersionUID = 1L;

    @EJB
    MyBean mybean;

    protected void doGet(HttpServletRequest request,
            HttpServletResponse response) throws ServletException, IOException {

        PrintWriter out = response.getWriter();
        mybean.increment();
        out.println(mybean.getNumber());
    }

}

我期望getNumber每次都返回0,但它返回1,并且浏览器中servlet的重新加载会进一步增加它。问题在于我对无状态会话Bean如何工作的理解,而不是与库或应用程序服务器一起工作,当然。有人可以给我一个简单的hello world类型的例子吗,一个无状态会话bean,当你把它改成有状态时,它的行为会有所不同?


答案 1

无状态会话 Bean (SLSB) 不绑定到一个客户端,并且不能保证一个客户端在每个方法调用时都能获得相同的实例(某些容器可能会在每个方法调用会话中创建和销毁 Bean,这是特定于实现的决策,但实例通常是池化的 - 我没有提到集群环境)。换句话说,尽管无状态 Bean 可能具有实例变量,但这些字段并不特定于一个客户端,因此在远程调用之间不要依赖它们。

相比之下,有状态会话 Bean (SFSB) 在其整个生命周期中专用于一个客户端,没有交换或池化实例(它可能会在钝化后从内存中逐出以节省资源,但这是另一回事)并保持会话状态。这意味着 Bean 的实例变量可以在方法调用之间保持相对于客户端的数据。这使得相互依赖的方法调用成为可能(由一个方法所做的更改会影响后续的方法调用)。多步骤流程(注册流程、购物车、预订流程等)是 SFSB 的典型用例。

还有一件事。如果您使用的是 SFSB,那么必须避免将它们注入到本质上是多线程的类中,例如 Servlet 和 JSF 托管 Bean(您不希望它被所有客户端共享)。如果要在 Web 应用程序中使用 SFSB,那么您需要执行 JNDI 查找并将返回的 EJB 实例存储在对象中以供将来活动。像这样:HttpSession

try {
    InitialContext ctx = new InitialContext();
    myStateful = (MyStateful)ctx.lookup("java:comp/env/MyStatefulBean");
    session.setAttribute("my_stateful", myStateful);
} catch (Exception e) {
    // exception handling
}

答案 2

重要的区别不是私有成员变量,而是将状态与特定用户相关联(想想“购物车”)。

有状态会话 Bean 的有状态部分类似于 servlet 中的会话。有状态会话 Bean 允许你的应用仍然具有该会话,即使没有 Web 客户端也是如此。当应用服务器从对象池中提取无状态会话 Bean 时,它知道它可用于满足任何请求,因为它不与特定用户关联。

有状态会话 Bean 必须分发给首先获取它的用户,因为他们的购物车信息应该只知道他们。应用服务器确保情况确实如此。想象一下,如果您可以开始购物,然后应用程序服务器在我出现时将您的有状态会话Bean交给我,那么您的应用程序将有多受欢迎!

所以你的私人数据成员确实是“状态”,但它不是“购物车”。尝试重做你的(非常好的)例子,以便增量变量与特定用户相关联。递增它,创建一个新用户,然后查看他们是否仍能看到递增的值。如果操作正确,每个用户都应该只看到他们版本的计数器。


推荐