我似乎无法找到一种方法来强制在启动Web应用程序时实例化/初始化应用程序范围的托管bean。似乎应用程序范围的bean在第一次访问bean时会进行惰性实例化,而不是在启动Web应用程序时实例化。对于我的Web应用程序,当第一个用户第一次在Web应用程序中打开页面时,就会发生这种情况。
我想避免这种情况的原因是因为在我的应用程序范围的bean初始化期间发生了许多耗时的数据库操作。它必须从持久存储中检索一堆数据,然后以ListItem元素等形式缓存一些频繁显示给用户的数据。我不希望在第一个用户连接时发生这一切,因此导致长时间的延迟。
我的第一个想法是使用旧式ServletContextListener contextInitialized()方法,并从那里使用ELResolver手动请求我的托管bean的实例(从而强制初始化发生)。不幸的是,我无法在此阶段使用ELResolver来触发初始化,因为ELResolver需要FacesContext,并且FacesContext仅在请求的生命周期内存在。
有没有人知道另一种方法来实现这个目标?
我使用MyFaces 1.2作为JSF实现,目前无法升级到2.x.
答案 0 :(得分:55)
我的第一个想法是使用旧式ServletContextListener contextInitialized()方法,并从那里使用ELResolver手动请求我的托管bean的实例(从而强制初始化发生)。不幸的是,我无法使用ELResolver在此阶段触发初始化,因为ELResolver需要FacesContext,并且FacesContext仅在请求的生命周期内存在。
不需要 复杂。只需实例化bean并将其放在应用程序范围内,并将相同的托管bean名称作为键。当已经存在于范围中时,JSF将重用 bean。使用基于Servlet API的JSF,ServletContext
表示应用程序范围(因为HttpSession
表示会话范围,HttpServletRequest
表示请求范围,每个范围都带有setAttribute()
和{{{ 1}}方法)。
应该这样做,
getAttribute()
其中public void contextInitialized(ServletContextEvent event) {
event.getServletContext().setAttribute("bean", new Bean());
}
应与"bean"
中应用程序作用域bean的<managed-bean-name>
相同。
仅仅为了记录,在JSF 2.x上您需要做的就是在faces-config.xml
bean上将eager=true
添加到@ManagedBean
。
@ApplicationScoped
然后在应用程序启动时自动实例化。
或者,当您通过CDI @ManagedBean(eager=true)
@ApplicationScoped
public class Bean {
// ...
}
管理支持bean时,请抓住OmniFaces @Eager
:
@Named
答案 1 :(得分:2)
据我所知,您无法强制在应用程序启动时实例化托管bean。
也许您可以使用ServletContextListener,而不是实例化您的托管bean,它将自己执行所有数据库操作?
另一种解决方案可能是在应用程序启动时手动实例化bean,然后将bean设置为ServletContext的属性。
以下是代码示例:
public class MyServletListener extends ServletContextListener {
public void contextInitialized(ServletContextEvent sce) {
ServletContext ctx = sce.getServletContext();
MyManagedBean myBean = new MyManagedBean();
ctx.setAttribute("myManagedBean", myManagedBean);
}
}
在我看来,这远不是干净的代码,但似乎它就是诀窍。
答案 2 :(得分:-3)
除了BalusC's answer above,您还可以使用 @Startup
和@Singleton
(CDI),例如
//@Named // javax.inject.Named: only needed for UI publishing
//@Eager // org.omnifaces.cdi.Eager: seems non-standard like taken @Startup below
@Startup // javax.ejb.Startup: like Eager, but more standard
@Singleton // javax.ejb.Singleton: maybe not needed if Startup is there
//@Singleton( name = "myBean" ) // useful for providing it with a defined name
@ApplicationScoped
public class Bean {
// ...
}
很好地解释了here。 至少在JPA 2.1中有效。