无状态和有状态 Enterprise Java Bean
我正在阅读 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
无状态会话 Bean (SLSB) 不绑定到一个客户端,并且无法保证一个客户端通过每次方法调用获得相同的实例(某些容器可能会创建和销毁beans 与每个方法调用会话,这是一个特定于实现的决定,但实例通常是池化的 - 而且我没有提到集群环境)。换句话说,虽然无状态 bean 可能有实例变量,但这些字段并不特定于某个客户端,因此
不要在远程调用之间依赖它们。
相比之下,有状态会话 Bean (SFSB) 在其整个生命周期中专用给一个客户端,没有实例的交换或池化(它可能会在钝化后从内存中逐出以节省资源,但这是另一回事了) )并保持对话状态。这意味着 bean 的实例变量可以在方法调用之间保存与客户端相关的数据。这使得相互依赖的方法调用成为可能(一个方法所做的更改会影响后续方法调用)。多步骤流程(注册流程、购物车、预订流程...)是 SFSB 的典型用例。
还有一件事。如果您使用 SFSB,那么您必须避免将它们注入到本质上是多线程的类中,例如 Servlet 和 JSF 托管 bean(您不希望它被所有客户端共享)。如果您想在 Web 应用程序中使用 SFSB,则需要执行 JNDI 查找并将返回的 EJB 实例存储在
HttpSession
对象中以供将来的活动使用。像这样的东西: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:重要的区别不是私有成员变量,而是将状态与特定用户相关联(想想“购物车”)。
有状态会话 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.
在这种情况下,无状态和有状态并不完全符合您的预期。
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:
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.
好问题,
试试这个代码(更改 MyBean 有状态/无状态。):
Servlet_1
Servlet_2
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.):
Servlet_1
Servlet_2
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
两种主要类型的会话 Bean 之间的主要区别是:
无状态 Bean
有状态 Bean
The major differences between the two major types of session beans are:
Stateless Beans
Stateful Beans
发生这种情况是因为容器池中只有一个 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.
它有很好的答案。我想补充一点小答案。 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".