I am quite new to EJB. I need stateful bean in my EAR application. I have created simple stateful session bean in an ejb module:
@Stateful
public class Test {
public Test() {
}
private int i;
@PostConstruct
public void initialize() {
i = 0;
}
public int getI() {
return i++;
}
}
And I call it from servlet in a war module:
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();
}
...
}
When I run it, the number gets bigger with each refresh of a browser.
0, 1, 2, ...
But when I run it in another browser, the number doesn't start from 0 but continues the session from the previous browser. It behaves like singleton.
3, 4, 5, ...
Why wasn't a new instance of the bean created? I tried to put the session bean into the war module, or annotate it with SessionScoped but result is the same.
Can you help me to create a new instance of the stateful bean for each http session?
A single servlet is created to service all requests. You're injecting an instance of a single stateful session bean into the servlet, so all requests will use that same stateful session bean. It is rarely useful to inject stateful session beans.
You need to create a per-HttpSession instance of the stateful session bean:
// 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);
}
...
}
}
Alternatively, if you have CDI, you could mark your stateful session bean as @SessionScoped and use @Inject for injection rather than @EJB.