有状态,无状态和单例EJB bean的结果相同

时间:2016-06-10 12:46:50

标签: java-ee singleton ejb stateless stateful

我正在尝试制作一个简单的@Stateful,@ Stateless和@Singleton EJB bean示例,以帮助我更好地理解这些差异。问题是当我使用@Stateful,@ Stateless或@Singleton注释中的任何一个注释bean时,没有任何区别。

这是豆子:

import javax.ejb.Singleton;
import javax.ejb.Stateful;
import javax.ejb.Stateless;


    @Stateful
    public class Bean {
        private int counter = 0;

        public int getCounter(){
            return counter++;
        }  
    }

这是Servlet客户端:

import java.io.IOException;
import java.io.PrintWriter;

import javax.ejb.EJB;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import javaeetutorial.converter.ejb.Bean;

@WebServlet(urlPatterns="/")
public class Client extends HttpServlet{

    @EJB
    Bean bean;

    protected void processRequest(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        response.setContentType("text/html;charset=UTF-8");
        PrintWriter out = response.getWriter();
        out.println("<html lang=\"en\">");
        out.println("<head>");
        out.println("<title>test</title>");
        out.println("</head>");
        out.println("<body>");
        out.println("<h1>Servlet ConverterServlet at " +
                request.getContextPath() + "</h1>");
        try {
            out.println("<form method=\"get\">");
            out.println("<input type=\"submit\" value=\"Submit\">");
            out.println("</form>");
            out.println("<p>" + bean.getCounter() + "</p>");    
            out.println("<p>" + bean + "</p>"); 
        } finally {
            out.println("</body>");
            out.println("</html>");
            out.close();
        }
    }

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        processRequest(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        processRequest(request, response);
    }

}

我的预期结果是:

@Statefull - 当每个不同的客户端按下按钮以查看从0开始的计数

@Singleton - 当任何客户按下按钮只能看到一个计数

@Stateless - 我不知道到底会发生什么

2 个答案:

答案 0 :(得分:1)

预期结果如下:

  • @Stateful - 有状态会话bean有超时,因此你应该永远将有状态会话bean注入一个长期存在的对象,例如servlet。相反,您应该只查找它们并使用它们(可能通过将引用插入到HttpSession中)。预期的结果是bean实例及其计数器将由所有请求共享,如果您发出并发请求,每个请求将阻止等待访问有状态会话bean(尝试向getCounter方法添加sleep,然后发出请求从多个浏览器选项卡/窗口)。如果您没有请求一段时间,那么bean将被删除,这将导致所有后续请求失败;您可以使用@StatefulTimeout(value=1, unit=TimeUnit.SECONDS)轻松观察此内容。

  • @Singleton - 所有请求都将共享bean实例及其计数器。默认情况下,单例使用容器管理的并发,因此在方法中一次只允许一个请求。同样,您可以向getCounter方法添加一个sleep来观察它。

  • @Stateless - 根据应用程序服务器的池配置,可能会根据需要为并发请求创建多个bean实例,并且可以跨请求重用bean实例。同样,您可以向getCounter方法添加一个sleep,并从多个浏览器选项卡/窗口发出请求以观察此情况。无状态会话bean旨在用于封装其他EJB服务(例如,事务,安全性,调度等),因此成员变量应仅用于缓存可以在不考虑客户端的情况下使用的状态(例如,缓存引用DataSource,UserTransaction等),而不是存储状态。

答案 1 :(得分:0)

你遇到的问题是webservlet被实例化一次(或者每个请求至少不会一次,这就是你需要清楚地看到它的区别),所以它是bean实例。因此,您使用哪种类型的bean(有状态,无状态,单例)没有区别,因为Bean实例始终依赖于同一个servlet实例。

如果您使用 requestScoped 资源,使用 singleton 注释,您将计算所请求的计数器的次数(所有请求共享同一个实例), 有状态您会看到客户请求计数器的次数,并且无状态将取决于。但是,因为计数器是一个状态,所以使用无状态bean(查看名称)是没有意义的。您可以将无状态理解为池化 ejb,因此每次需要bean时,服务器都将获取无状态池的实例。一个优点是bean的性能,因为它们已经被创建到池中(检查无状态池配置),它们真的很快就可以使用了。

您可以找到更多信息here