【问题标题】:Issue with stateful EJB - keeps one session for all users有状态 EJB 的问题 - 为所有用户保留一个会话
【发布时间】:2012-05-07 06:52:51
【问题描述】:

我对 EJB 很陌生。我的 EAR 应用程序中需要有状态 bean。我在 ejb 模块中创建了简单的有状态会话 bean:

@Stateful
public class Test {

    public Test() {
    }

    private int i;

    @PostConstruct
    public void initialize() {
        i = 0;
    }

    public int getI() {
        return i++;
    }
}

我从一个战争模块中的 servlet 调用它:

public class TestServlet extends HttpServlet {

    @EJB
    Test test;

    protected void processRequest(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        response.setContentType("text/html;charset=UTF-8");
        PrintWriter out = response.getWriter();

        HttpSession session = request.getSession(true);

        out.println("<html>");
        out.println("<head>");
        out.println("<title></title>");            
        out.println("</head>");
        out.println("<body>");
        out.println("<h1>" + test.getI() + "</h1>");
        out.println("</body>");
        out.println("</html>");         
        out.close();
    }
...
}

当我运行它时,每次刷新浏览器,这个数字都会变大。

0, 1, 2, ...

但是当我在另一个浏览器中运行它时,数字不是从 0 开始,而是从前一个浏览器继续会话。它的行为类似于单例。

3, 4, 5, ...

为什么没有创建 bean 的新实例?我尝试将会话 bean 放入 war 模块中,或者使用 SessionScoped 对其进行注释,但结果是一样的。

您能帮我为每个 http 会话创建一个有状态 bean 的新实例吗?

【问题讨论】:

    标签: session ejb stateful


    【解决方案1】:

    创建一个 servlet 来服务所有请求。您将单个有状态会话 bean 的实例注入到 servlet 中,因此所有请求都将使用同一个有状态会话 bean。注入有状态会话 bean 很少有用。

    您需要创建一个有状态会话 bean 的 per-HttpSession 实例:

    // Declare the reference without injection...
    @EJB(name="ejb/test" beanInterface=Test.class)
    public class TestServlet extends HttpServlet {
        protected void processRequest(HttpServletRequest request, HttpServletResponse response)
                throws ServletException, IOException {
            response.setContentType("text/html;charset=UTF-8");
            PrintWriter out = response.getWriter();
    
            HttpSession session = request.getSession(true);
            Test bean = session.getAttribute(BEAN);
            if (bean == null) {
                try {
                    // ...and then create an instance by looking it up from java:comp/env
                    bean = (Test)new InitialContext().lookup("java:comp/env/ejb/test");
                } catch (NamingException ex) { ... }
                session.setAttribute(BEAN, bean);
            }
    
            ...
        }
    }
    

    或者,如果您有 CDI,您可以将有状态会话 bean 标记为 @SessionScoped 并使用 @Inject 而不是 @EJB 进行注入。

    【讨论】:

    • 感谢您的回答。我尝试了 SessionScoped,但它没有用。我的错误是我使用 EJB 获取实例,但它应该使用 Inject。所以现在我很高兴地使用 SessionScoped Stateful 并使用 Inject 进行注入,它可以工作。
    • 啊,是的,我忘了提到@Inject。更新答案,谢谢。
    猜你喜欢
    • 2012-04-04
    • 2015-03-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-17
    • 2012-12-28
    • 2014-11-20
    • 1970-01-01
    相关资源
    最近更新 更多