Multi-threaded access to EJB references
As I've seen a lot of access to the blog from english speaking countries, I'll start to blog in english from now on.
Well, since the Java EE spec was out I always had a doubt regarding how an EJB reference works when it's left in a multi-threaded environment like when used as an instance property of a servlet.
With annotations, this has grown very popular as it's common to specify the bean reference as an instance property and annotate it with @EJB. Here is what I've found regarding this subject:
For stateless beans the specification tells the following:
There is no need for any restrictions against concurrent client access to stateless session beans because the container routes each request to a different instance of the stateless session bean class.
This can be proved creating a stateless session bean like the one bellow:
@Stateless
public class MyStatelessBean implements MyStatelessBeanLocal {
public String whoAmI() {
try {
Thread.sleep(100);
} catch (Exception e) {
}
String thisDesc = this.toString();
System.out.println(thisDesc);
return thisDesc;
}
}
And a servlet like the following one:
@WebServlet(name = "StatelessTestServlet", urlPatterns = {"/StatelessTestServlet"})
public class StatelessTestServlet extends HttpServlet {
@EJB
private MyStatelessBeanLocal myStatelessBean;
protected void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
response.setBufferSize(0);
PrintWriter out = response.getWriter();
try {
out.println("<p>" + myStatelessBean.whoAmI() + "</p>");
} finally {
out.close();
}
}
//doGet & doPost omitted for clarity purposes
}
Creating a test in JMeter to call this Servlet with 1 thread and an interval between the calls of 1 second, we see the following in Glassfish output:
INFO: br.com.amadei.ejb.MyStatelessBean@4fe98e
INFO: br.com.amadei.ejb.MyStatelessBean@4fe98e
INFO: br.com.amadei.ejb.MyStatelessBean@4fe98e
INFO: br.com.amadei.ejb.MyStatelessBean@4fe98e
INFO: br.com.amadei.ejb.MyStatelessBean@4fe98e
INFO: br.com.amadei.ejb.MyStatelessBean@4fe98e
This shows that the same stateless EJB is handling the requests. This is up to the container but as there is no load, the same EJB is able to do the job.
If multiple requests come in from JMeter, we see the following:
INFO: br.com.amadei.ejb.MyStatelessBean@4fe98e
INFO: br.com.amadei.ejb.MyStatelessBean@4fe98e
INFO: br.com.amadei.ejb.MyStatelessBean@183a9a
INFO: br.com.amadei.ejb.MyStatelessBean@183a9a
INFO: br.com.amadei.ejb.MyStatelessBean@4fe98e
INFO: br.com.amadei.ejb.MyStatelessBean@b229f7
INFO: br.com.amadei.ejb.MyStatelessBean@325538
INFO: br.com.amadei.ejb.MyStatelessBean@4fe98e
INFO: br.com.amadei.ejb.MyStatelessBean@183a9a
This shows that multiple requests were sent to multiple EJB instances using the same reference, much the same way as described by the specification.
For Stateful beans the specification tells the following:
By default, clients are allowed to make concurrent calls to a stateful session object and the container is required to serialize such concurrent requests. Note that the container never permits multi-threaded access to the actual stateful session bean instance.
According to the spec you can even specify timeouts to this serialized access (see page 82 of the EJB 3.1 specification) but as the Stateful beans are tied to the client invoking them, it's not a good idea to use them as annotated properties of your Servlets, just lookup them or reuse the reference added to the HttpSession.