无状态和有状态 Enterprise Java Bean

发布于 2024-08-22 21:26:10 字数 1265 浏览 10 评论 0原文

我正在阅读 Java EE 6 教程,并试图了解无状态会话 Bean 和有状态会话 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++;
    }
}

我期望 getNumber 每次都返回 0的客户端

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

}

,但它返回 1 并且在浏览器中重新加载 servlet 会增加更多。问题在于我对无状态会话 Bean 如何工作的理解,当然与库或应用程序服务器无关。有人能给我一个简单的 hello world 类型的无状态会话 bean 示例,当您将其更改为有状态时,它的行为会有所不同吗?

I am going through the Java EE 6 tutorial and I am trying to understand the difference between stateless and stateful session beans. If stateless session beans do not retain their state in between method calls, why is my program acting the way it is?

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. The problem is with my understanding of how stateless session beans work and not with the libraries or application server, of course. Can somebody give me a simple hello world type example of a stateless session bean that behaves differently when you change it to stateful?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

你怎么这么可爱啊 2024-08-29 21:26:10

无状态会话 Bean (SLSB) 不绑定到一个客户端,并且无法保证一个客户端通过每次方法调用获得相同的实例(某些容器可能会创建和销毁beans 与每个方法调用会话,这是一个特定于实现的决定,但实例通常是池化的 - 而且我没有提到集群环境)。换句话说,虽然无状态 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
}

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). 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.

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. This means that the instance variables of the bean can keep data relative to the client between method invocations. 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.

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). 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. 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
}
分分钟 2024-08-29 21:26:10

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

有状态会话 bean 的有状态部分类似于 servlet 中的会话。有状态会话 Bean 允许您的应用程序在没有 Web 客户端的情况下仍然拥有该会话。当应用程序服务器从对象池中获取无状态会话 bean 时,它知道它可以用于满足任何请求,因为它与特定用户无关。

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

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

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. Stateful session beans allow your app to still have that session even if there isn't a web client. 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.

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. 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!

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.

青衫负雪 2024-08-29 21:26:10

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

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

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

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

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

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

Stateless and stateful in this context don't mean quite what you might expect.

Statefulness with EJBs refers to what I call conversational state. 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. A stateful session bean can maintain this kind of conversation so it remembers what happens between calls.

Stateless session beans don't have such capacity for conversational state.

Global variables inside a session bean (stateless or stateful) are something else entirely. 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.

强者自强 2024-08-29 21:26:10

好问题,

试试这个代码(更改 MyBean 有状态/无状态。):

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

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

}

case : 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

Good Question,

try this code (change 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

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

}

case : 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

case : 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

苏别ゝ 2024-08-29 21:26:10

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

无状态 Bean

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

有状态 Bean

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

The major differences between the two major types of session beans are:

Stateless Beans

  1. Stateless Session Beans are the ones which have no conversational state with the client which has called its methods. 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.
  3. They can handle multiple requests from multiple clients in parallel.

Stateful Beans

  1. Stateful session beans can maintain the conversational state with multiple clients at a time and the task is not shared between the
    clients.
  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.
留蓝 2024-08-29 21:26:10

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

This thing happen because the container only has one bean instance in the pool that is being reused for all calls. If you run the clients in parallel you will see a different result because the container will create more bean instances in the pool.

长安忆 2024-08-29 21:26:10

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

It has good answers. I would like to add small answer. Stateless Bean should not used to hold any client data. It should be used to "to model actions or processes that can be done in one shot".

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文