I can't seem to find a way to force an application-scoped managed bean to be instantiated/initialized when the web app is started. It seems that application-scoped beans get lazy-instantiated the first time the bean is accessed, not when the web app is started up. For my web app this happens when the first user opens a page in the web app for the first time.
The reason I want to avoid this is because a number of time-consuming database operations happen during the initialization of my application-scoped bean. It has to retrieve a bunch of data from persistent storage and then cache some of it that will be frequently displayed to the user in the form of ListItem elements, etc. I don't want all that to happen when the first user connects and thus cause a long delay.
My first thought was to use an old style ServletContextListener contextInitialized() method and from there use an ELResolver to manually request the instance of my managed bean (thus forcing the initialization to happen). Unfortunately, I can't use an ELResolver to trigger the initialization at this stage because the ELResolver needs a FacesContext and the FacesContext only exists during the lifespan of a request.
Does anyone know of an alternate way to accomplish this?
I am using MyFaces 1.2 as the JSF implementation and cannot upgrade to 2.x at this time.
Romain Manni-Bucau posted a neat solution to this that uses CDI 1.1 on his blog.
The trick is to let the bean observe the initialization of the built-in lifecycle scopes, i.e.
ApplicationScoped
in this case. This can also be used for shutdown cleanup. So an example looks like this:As far as I know, you can't force a managed bean to be instantiated at application startup.
Maybe you could use a ServletContextListener which, instead of instantiating your managed bean, will perform all the database operations itself?
Another solution might be to instantiate your bean manually at application startup, and then set the bean as an attribute of your ServletContext.
Here is a code sample:
In my opinion, this is far from clean code, but it seems like it does the trick.
It doesn't need to be that complicated. Just instantiate the bean and put it in the application scope with the same managed bean name as key. JSF will just reuse the bean when already present in the scope. With JSF on top of Servlet API, the
ServletContext
represents the application scope (asHttpSession
represents the session scope andHttpServletRequest
represents the request scope, each withsetAttribute()
andgetAttribute()
methods).This should do,
where
"bean"
should be the same as the<managed-bean-name>
of the application scoped bean infaces-config.xml
.Just for the record, on JSF 2.x all you need to do is to add
eager=true
to@ManagedBean
on an@ApplicationScoped
bean.It will then be auto-instantiated at application startup.
Or, when you're managing backing beans by CDI
@Named
, then grab OmniFaces@Eager
:Additionally to BalusC's answer above you could use
@Startup
and@Singleton
(CDI), e.g.which is nicely explained here. Works in JPA 2.1 at least.