When using @EJB, does each managed bean get its own @EJB instance?
I am using JSF 2.2 for a web project and I am implementing the login page now.
I have a login.xhtml
that serves as the view, and a backing bean called UserLoginView
.
This bean has an EJB
property bean private UserService userService
(as shown here).
Does this mean that each new UserLoginView
gets a new instance of UserService
?
Is OK to implement it like this in a production environment?
Does this mean that each new UserLoginView gets a new instance of UserService?
Nope. The given UserService
is a @Stateless
EJB. @Stateless
EJBs are pooled and injected as serializable proxies autogenerated by the container. Among others the stack trace when an exception occurs from an EJB is evidence for this. You see extra layers between the backing bean method and the EJB method.
The autogenerated proxy class for a @Stateless
EJB looks roughly like this (in reality it's more complex, e.g. DB transaction also needs to be obtained, started and committed here depending on the @TransactionAttribute
of the EJB class and/or method):
public class UserServiceProxy extends UserService implements Serializable {
public User find(Long id) {
UserService instance = getAnAvailableInstanceFromPool();
User result = instance.find(id);
releaseInstanceToPool(instance);
return result;
}
public Long save(User user) {
UserService instance = getAnAvailableInstanceFromPool();
Long result = instance.save(user);
releaseInstanceToPool(instance);
return result;
}
// ...
}
Do you see it? It just grabs an available instance from the EJB pool and then delegates the method call to it and finally releases it to the pool for future reuse. It's exactly this proxy instance which is actually being injected in your JSF managed bean.
CDI works also this way by the way. That's exactly why it's with CDI possible to inject a bean of a narrower scope in a bean of a wider scope and still get it to work as intented. JSF's @ManagedBean
injects the actual instance and therefore it doesn't work that way. It would have worked if JSF also used proxies which actually grabbed the current bean instance via FacesContext
and delegated to it.
Only @Stateful
EJBs are actually tied to the lifetime of the client. In case of managed bean as client, it would indeed get "its own" instance. See also JSF request scoped bean keeps recreating new Stateful session beans on every request?
And @Singleton
EJBs have basically a maximum of one instance in the pool. So each client will always get the same instance.
Is ok to implement it like this in a production environment?
Absolutely. Otherwise they didn't exist.