繁体   English   中英

无状态和有状态企业 Java Bean

[英]Stateless and Stateful Enterprise Java Beans

我正在阅读 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 示例,当您将其更改为有状态时,它的行为会有所不同吗?

无状态会话 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
}

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

有状态会话 bean 的有状态部分类似于 servlet 中的会话。 即使没有 Web 客户端,有状态会话 bean 也允许您的应用程序仍然具有该会话。 当应用服务器从对象池中取出一个无状态会话 bean 时,它知道它可以用来满足任何请求,因为它与特定用户无关。

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

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

在这种情况下,无状态和有状态并不完全符合您的预期。

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

  • 预订座位
  • 充值信用卡
  • 出票

想象其中的每一个都是对会话 bean 的方法调用。 有状态会话 bean 可以维护这种对话,以便记住调用之间发生的情况。

无状态会话 bean 没有这样的对话状态能力。

会话 bean(无状态或有状态)中的全局变量完全是另一回事。 有状态会话 bean 将创建一个 bean 池(因为一个 bean 一次只能在一个对话中使用)而无状态会话 bean 通常只有一个实例,这将使全局变量起作用,但我不认为这是必然的保证。

好问题,

试试这个代码(改变 MyBean Stateful/Stateless。):

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

@LocalBean 
@Stateless 
public class MyBean {

    private int number = 0;

    public int getNumber() {
        return number;
    }

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

小服务程序_1

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

    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());
        }

    }

Servlet_2

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

import java.io.PrintWriter;

@WebServlet(name = "NewServletClient", urlPatterns = { "/NewServletClient" })
public class NewServletClient 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());
    }

}

案例:MyBean -@Stateless

http://localhost:8080/MYServletDemo/ ServletClient

1

http://localhost:8080/MYServletDemo/ ServletClient

2

http://localhost:8080/MYServletDemo_war_exploded/ newServletClient

3

http://localhost:8080/MYServletDemo/ ServletClient

4

案例:MyBean -@Stateful

http://localhost:8080/MYServletDemo/ ServletClient

1

http://localhost:8080/MYServletDemo/ ServletClient

2

http://localhost:8080/MYServletDemo/ newServletClient

1

http://localhost:8080/MYServletDemo/ ServletClient

3

两种主要类型的会话 bean 之间的主要区别是:

无状态 Bean

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

有状态的 Bean

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

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM