如何强制应用程序范围的bean在应用程序启动时实例化?

时间:2010-08-30 12:57:06

标签: jsf initialization startup managed-bean

我似乎无法找到一种方法来强制在启动Web应用程序时实例化/初始化应用程序范围的托管bean。似乎应用程序范围的bean在第一次访问bean时会进行惰性实例化,而不是在启动Web应用程序时实例化。对于我的Web应用程序,当第一个用户第一次在Web应用程序中打开页面时,就会发生这种情况。

我想避免这种情况的原因是因为在我的应用程序范围的bean初始化期间发生了许多耗时的数据库操作。它必须从持久存储中检索一堆数据,然后以ListItem元素等形式缓存一些频繁显示给用户的数据。我不希望在第一个用户连接时发生这一切,因此导致长时间的延迟。

我的第一个想法是使用旧式ServletContextListener contextInitialized()方法,并从那里使用ELResolver手动请求我的托管bean的实例(从而强制初始化发生)。不幸的是,我无法在此阶段使用ELResolver来触发初始化,因为ELResolver需要FacesContext,并且FacesContext仅在请求的生命周期内存在。

有没有人知道另一种方法来实现这个目标?

我使用MyFaces 1.2作为JSF实现,目前无法升级到2.x.

3 个答案:

答案 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中有效。