In the book "EJB 3 in Action" (by Debu Panda, Reza Rahman and Derek Lane) I've found the following passage:
"Keep in mind that you must not inject a stateful session bean into a stateless object, such as stateless session bean or servlet that may be
shared by multiple concurrent clients (you should use JNDI in such cases instead)."
Could someone please elaborate on that ? I don't see how JNDI could help in such a case and why dependency injection is an issue.
(I realize that using a stateful bean inside a stateless one is not very useful, since after each method call the stateless object "forgets the state".)
Well I'm not a pro at this but I did some research on the internet. I think the default behavior of StatelessSessionBeans is that the container manages a pool of its objects and uses a unique object to sever a request. Now this behavior can be modified using @ConcurrencyManagement(BEAN) annotation. The explanation given in the book definitely applies to Servlets. This is because EJBs are injected at class level. And the same servlet instance is used to serve all the client request for that URL pattern. So the same stateful session bean would be shared to respond to all requests which is not the correct behavior as different clients will share same data in the stateful session bean. I think by lookup, the book authors are mentioning to lookups done inside the doGet or doPost method so that there is a different bean instance to respond to each request.
I may be wrong here as I don't know much about this and I couldn't find much over the internet. Maybe injection leads to same stateful session bean injected into multiple stateless session beans and servlets or something else but I thought I should put forward my point of view as you've not got any other response...
The Java EE specs say that when you do a JNDI lookups, the object returned must be a unique instance (apart from very few exceptions, like shared connection factories, immutable objects etc). When you specify that a certain field / property needs dependency injection, the container performs injection after the constructor runs, and it is implemented as a JNDI lookup under the hood.
Now, the thing is that stateless objects (stateless session beans - SLSB or servlets) are not linked to any particular client, and for example, there is generally only one servlet instance per web context. So, if any SFSB (statefull session bean) was injected in a servlet, all requests would be able to put / get data into it, even the ones that are totally unrelated (not part of the same HTTP session). The same is for SLSB - when a bean is created, a SFSB would be injected for each SLSB in the pool (each would have its own instance), but you can never tell which bean serves requests of which client, so you could basically end up being able to read state that another client has set - just like in a case of a servlet.
However, there are ways to bypass this - and these are explicit JNDI lookups. For example, when each HTTP request comes in for a servlet, each would have a JNDI lookup call, and each request would get its very own instance of a SFSB (again, this is a requirement of Java EE specs). It could then store it in a HttpSession. The same for SLSB - explicit JNDI lookups in a method return new instances of SFSB, and these would be scoped for the given SLSB business method call - note there are test cases where it is usefull to be able to call another bean's methods in a sequence, and be sure that the same instance is used.
To answer your question, in short if you DI stateful session bean to a Servlet, the Servlet is shared by many clients, if a client call remove on the SFSB, then another client try to use that SFSB, your application is come to an end (an exception will be thrown).
Hope this helps.
SCJA 1.0, SCJP 1.4, SCWCD 1.4, SCBCD 1.3, SCJP 5.0, SCEA 5, SCBCD 5; OCUP - Fundamental, Intermediate and Advanced; IBM Certified Solution Designer - OOAD, vUML 2; SpringSource Certified Spring Professional
Joined: Nov 30, 2008
Thanks for your answers.
The really unclear issue was why would you inject a stateful bean into a stateless one (even using JNDI) ? But I guess there are scenarios where you
need to do something like this:
1. call a stateless bean method
1.1 stateful bean proxy = JNDI lookup
1.2 stateful bean proxy -> call method 1
1.3 stateful bean proxy -> call method 2
1.4 stateful bean proxy -> call method 3
Do you have real life examples of this kind ?
The scenario where you'd use a stateful bean from a servlet is clear: a typical web shopping cart application (like the Java petstore).