简体   繁体   English

无状态和有状态企业 Java Bean

[英]Stateless and Stateful Enterprise Java Beans

I am going through the Java EE 6 tutorial and I am trying to understand the difference between stateless and stateful session beans.我正在阅读 Java EE 6 教程,并试图了解无状态和有状态会话 bean 之间的区别。 If stateless session beans do not retain their state in between method calls, why is my program acting the way it is?如果无状态会话 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++;
    }
}

The client客户端

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

}

I was expecting getNumber to return 0 every time but it is returning 1 and reloads of the servlet in my browser increase it more.我期待 getNumber 每次都返回 0 但它返回 1 并且在我的浏览器中重新加载 servlet 会增加它。 The problem is with my understanding of how stateless session beans work and not with the libraries or application server, of course.问题在于我对无状态会话 bean 如何工作的理解,而不是库或应用程序服务器,当然。 Can somebody give me a simple hello world type example of a stateless session bean that behaves differently when you change it to stateful?有人能给我一个简单的 hello world 类型的无状态会话 bean 示例,当您将其更改为有状态时,它的行为会有所不同吗?

Stateless Session Beans (SLSB) are not tied to one client and there is no guarantee for one client to get the same instance with each method invocation (some containers may create and destroy beans with each method invocation session, this is an implementation-specific decision, but instances are typically pooled - and I don't mention clustered environments).无状态会话 Bean (SLSB)不绑定到一个客户端,并且不能保证一个客户端在每次方法调用时获得相同的实例(一些容器可能会在每个方法调用会话中创建和销毁 bean,这是一个特定于实现的决定,但实例通常是池化的 - 我没有提到集群环境)。 In other words, although stateless beans may have instance variables, these fields are not specific to one client, so don't rely on them between remote calls.换句话说,虽然无状态 bean 可能有实例变量,但这些字段并不是特定于一个客户端的,所以不要在远程调用之间依赖它们。

In contrast, Stateful Session Beans (SFSB) are dedicated to one client for their entire life, there is no swapping or pooling of instances (it may be evicted from memory after passivation to save resources but that's another story) and maintain conversational state .相比之下,有状态会话 Bean (SFSB)专用于一个客户端的整个生命周期,没有实例的交换或池化(钝化后可能会从内存中逐出以节省资源,但这是另一回事)并保持对话状态 This means that the instance variables of the bean can keep data relative to the client between method invocations.这意味着 bean 的实例变量可以在方法调用之间保留与客户端相关的数据。 And this makes possible to have interdependent method calls (changes made by one method affect subsequent method calls).这使得可以进行相互依赖的方法调用(一种方法所做的更改会影响后续的方法调用)。 Multi-step processes (a registration process, a shopping cart, a booking process...) are typical use cases for SFSB.多步骤流程(注册流程、购物车、预订流程……)是 SFSB 的典型用例。

One more thing.还有一件事。 If you are using SFSB, then you must avoid injecting them into classes that are multithreaded in nature, such as Servlets and JSF managed beans (you don't want it to be shared by all clients).如果您正在使用 SFSB,那么您必须避免将它们注入到本质上是多线程的类中,例如 Servlet 和 JSF 托管 bean(您不希望它被所有客户端共享)。 If you want to use SFSB in your web application, then you need to perform a JNDI lookup and store the returned EJB instance in the HttpSession object for future activity.如果要在 Web 应用程序中使用 SFSB,则需要执行 JNDI 查找并将返回的 EJB 实例存储在HttpSession对象中以供将来活动使用。 Something like that:类似的东西:

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

The important difference is not private member variables, but associating state with a particular user (think "shopping cart").重要的区别不是私有成员变量,而是将状态与特定用户相关联(想想“购物车”)。

The stateful piece of stateful session bean is like the session in servlets.有状态会话 bean 的有状态部分类似于 servlet 中的会话。 Stateful session beans allow your app to still have that session even if there isn't a web client.即使没有 Web 客户端,有状态会话 bean 也允许您的应用程序仍然具有该会话。 When the app server fetches a stateless session bean out of the object pool, it knows that it can be used to satisfy ANY request, because it's not associated with a particular user.当应用服务器从对象池中取出一个无状态会话 bean 时,它知道它可以用来满足任何请求,因为它与特定用户无关。

A stateful session bean has to be doled out to the user that got it in the first place, because their shopping cart info should be known only to them.有状态会话 bean 必须首先分发给获得它的用户,因为他们的购物车信息应该只有他们知道。 The app server ensures that this is so.应用服务器确保如此。 Imagine how popular your app would be if you could start shopping and then the app server gave your stateful session bean to me when I came along!想象一下,如果您可以开始购物,然后应用服务器在我出现时将您的有状态会话 bean 提供给我,那么您的应用程序会有多受欢迎!

So your private data member is indeed "state", but it's not "shopping cart".所以你的私人数据成员确实是“状态”,但它不是“购物车”。 Try to redo your (very good) example to make it so the incremented variable is associated with a particular user.尝试重做您的(非常好的)示例以使其增加的变量与特定用户相关联。 Increment it, create a new user, and see if they can still see the incremented value.增加它,创建一个新用户,看看他们是否仍然可以看到增加的值。 If done correctly, every user should see just their version of the counter.如果操作正确,每个用户都应该只看到他们的计数器版本。

Stateless and stateful in this context don't mean quite what you might expect.在这种情况下,无状态和有状态并不完全符合您的预期。

Statefulness with EJBs refers to what I call conversational state . EJB 的状态指的是我所说的会话状态 The classic example is a flight booking.典型的例子是机票预订。 If it consists of three steps:如果它由三个步骤组成:

  • Reserve seat预订座位
  • Charge credit card充值信用卡
  • Issue Ticket出票

Imagine each of those is a method call to a session bean.想象其中的每一个都是对会话 bean 的方法调用。 A stateful session bean can maintain this kind of conversation so it remembers what happens between calls.有状态会话 bean 可以维护这种对话,以便记住调用之间发生的情况。

Stateless session beans don't have such capacity for conversational state.无状态会话 bean 没有这样的对话状态能力。

Global variables inside a session bean (stateless or stateful) are something else entirely.会话 bean(无状态或有状态)中的全局变量完全是另一回事。 Stateful session beans will have a pool of beans created (since a bean can only be used in one conversation at a time) whereas stateless sesion beans will often only have one instance, which will make the global variable works, but I don't think this is necessarily guaranteed.有状态会话 bean 将创建一个 bean 池(因为一个 bean 一次只能在一个对话中使用)而无状态会话 bean 通常只有一个实例,这将使全局变量起作用,但我不认为这是必然的保证。

Good Question,好问题,

try this code (change MyBean Stateful/Stateless.):试试这个代码(改变 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++;
    }
}

Servlet_1小服务程序_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 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());
    }

}

case : MyBean -@Stateless案例:MyBean -@Stateless

http://localhost:8080/MYServletDemo/ ServletClient http://localhost:8080/MYServletDemo/ ServletClient

1 1

http://localhost:8080/MYServletDemo/ ServletClient http://localhost:8080/MYServletDemo/ ServletClient

2 2

http://localhost:8080/MYServletDemo_war_exploded/ newServletClient http://localhost:8080/MYServletDemo_war_exploded/ newServletClient

3 3

http://localhost:8080/MYServletDemo/ ServletClient http://localhost:8080/MYServletDemo/ ServletClient

4 4

case : MyBean -@Stateful案例:MyBean -@Stateful

http://localhost:8080/MYServletDemo/ ServletClient http://localhost:8080/MYServletDemo/ ServletClient

1 1

http://localhost:8080/MYServletDemo/ ServletClient http://localhost:8080/MYServletDemo/ ServletClient

2 2

http://localhost:8080/MYServletDemo/ newServletClient http://localhost:8080/MYServletDemo/ newServletClient

1 1

http://localhost:8080/MYServletDemo/ ServletClient http://localhost:8080/MYServletDemo/ ServletClient

3 3

The major differences between the two major types of session beans are:两种主要类型的会话 bean 之间的主要区别是:

Stateless Beans无状态 Bean

  1. Stateless Session Beans are the ones which have no conversationa l state with the client which has called its methods.无状态会话 Bean是那些与调用其方法的客户端没有对话状态的会话 Bean For this reason they can create a pool of objects which can be used to interact with multiple clients.出于这个原因,他们可以创建一个可用于与多个客户端交互的对象池。
  2. Performance wise stateless beans are better since they don't have states per client.性能明智的无状态 bean更好,因为它们没有每个客户端的状态。
  3. They can handle multiple requests from multiple clients in parallel.它们可以并行处理来自多个客户端的多个请求。

Stateful Beans有状态的 Bean

  1. Stateful session beans can maintain the conversationa l state with multiple clients at a time and the task is not shared between the clients.有状态会话 bean 可以同时保持与多个客户端的会话状态,并且任务不在客户端之间共享。
  2. After the session is completed the state is not retained.会话完成后,状态不会保留。
  3. The container can serialize and store the state as a stale state for future use.容器可以将状态序列化并存储为陈旧状态以备将来使用。 This is done to save resources of the application server and to support bean failures.这样做是为了节省应用程序服务器的资源并支持 bean 故障。

This thing happen because the container only has one bean instance in the pool that is being reused for all calls.发生这种情况是因为容器在池中只有一个 bean 实例被所有调用重用。 If you run the clients in parallel you will see a different result because the container will create more bean instances in the pool.如果您并行运行客户端,您将看到不同的结果,因为容器将在池中创建更多 bean 实例。

It has good answers.它有很好的答案。 I would like to add small answer.我想补充一点小答案。 Stateless Bean should not used to hold any client data.无状态 Bean 不应用于保存任何客户端数据。 It should be used to "to model actions or processes that can be done in one shot".它应该用于“对可以一次性完成的动作或过程进行建模”。

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

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