无状态和有状态的企业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 worldtypes的无状态会话bean的例子,当你把它改变为有状态时,它的行为是不同的吗?

重要的区别不是私有成员variables,而是与特定用户(认为“购物车”)关联状态。

有状态会话bean的有状态就像servlet中的会话。 有状态会话bean允许您的应用程序即使没有Web客户端仍然拥有该会话。 当应用程序服务器从对象池中提取无状态会话bean时,它知道它可以用来满足任何请求,因为它不与特定的用户关联。

一个有状态的会话bean必须分配给用户,因为他们的购物车信息应该只被他们知道。 应用程序服务器确保如此。 想象一下,如果你可以开始购物,那么应用程序将会是多么的受欢迎,然后当我来到时,应用程序服务器给了你有状态的会话bean。

所以你的私人数据成员确实是“国家”,但它不是“购物车”。 尝试重做你的(非常好的)例子,使增量variables与特定的用户相关联。 增加它,创build一个新的用户,看看他们是否仍然可以看到增加的值。 如果正确完成,每个用户应该只看到他们的计数器的版本。

无状态会话Bean(SLSB) 不与一个客户端绑定 ,并且不保证一个客户端在每个方法调用中获得相同的实例(某些容器可能会在每个方法调用会话中创build和销毁Bean,这是一个实现特定的决定,但实例通常是集中的 – 我没有提到集群环境)。 换句话说,尽pipe无状态bean可能有实例variables,但这些字段并不是特定于一个客户端的,所以不要在远程调用之间依赖它们。

相反,有状态会话Bean(Stateful Session Beans,SFSB)是一生致力于一个客户,不存在实例交换或聚合(在钝化之后可能会从内存中被驱逐出去,这是另外一个故事)并保持对话状态 。 这意味着bean的实例variables可以在方法调用之间保留与客户端相关的数据。 这使得可能有相互依赖的方法调用(由一个方法所做的更改会影响后续的方法调用)。 多步骤stream程(注册stream程,购物车,预订stream程…)是SFSB的典型用例。

还有一件事。 如果您使用的是SFSB,那么您必须避免将它们注入本质上为multithreading的类,例如Servlets和JSF受pipeBean(您不希望它被所有客户端共享)。 如果要在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 } 

在这种情况下,无状态和有状态并不意味着你可能期望的。

EJB的状态指的是我所谓的对话状态 。 典型的例子是机票预定。 如果它由三个步骤组成:

  • 预留座位
  • 收取信用卡
  • 发行票

想象一下,这些都是调用会话bean的方法。 有状态会话bean可以维护这种会话,以便记住调用之间发生的事情。

无状态会话bean不具备会话状态的能力。

会话bean中的全局variables(无状态或有状态)是完全不同的。 有状态会话bean将创build一个bean池(因为一次只能在一个对话中使用bean),而无状态的会话bean通常只有一个实例,这将使全局variables有效,但我不认为这一定是有保证的。

发生这种情况的原因是容器中只有一个正在被所有调用重用的bean实例。 如果您并行运行客户端,则会看到不同的结果,因为容器将在池中创build更多的bean实例。

两种主要types会话bean的主要区别是:

无国籍的豆类

  1. 无状态会话Bean是与客户端没有对话状态的方式。 为此,他们可以创build一个可用于与多个客户端进行交互的对象池。
  2. 性能明智的无状态bean更好,因为它们没有每个客户的状态。
  3. 他们可以并行处理来自多个客户端的多个请求。

有状态的豆子

  1. 有状态会话bean一次可以保持与多个客户端的会话状态,并且不在客户端之间共享任务。
  2. 会话完成后,状态不会保留。
  3. 容器可以序列化并将状态存储为陈旧状态以供将来使用。 这样做是为了节省应用程序服务器的资源,并支持bean失败。

它有很好的答案。 我想补充一点答案。 无状态Bean不应该用来保存任何客户端数据。 应该用它来“模拟可以一次完成的动作或过程”。