2008-11-24 145 views
16

我正在构建一个JSF + Facelets Web应用程序,其中一部分是每隔一段时间扫描一次目录并索引任何更改的方法。此方法是处于应用程序范围内的bean的一部分。我已经构建了TimerTask的子类来每X毫秒调用一次该方法。我的问题是让bean初始化。我可以在页面上引用bean,当我进入页面时,bean被初始化,并按照指示工作;我想要的是在Web上下文初始化时初始化bean,以便它不需要页面访问来启动索引方法。谷歌已经展示了一些想要这种功能的人,但除了与Spring集成之外没有真正的解决方案,我真的不想仅仅为了获得这一功能。当上下文初始化时,JSF初始化应用程序bean

我试着玩过两个带有“加载启动时”设置的Servlet,还有一个ServletContextListener让事情继续下去,并且无法获得设置权限,要么是因为没有可用的FacesContext,或者因为我无法从JSF环境中引用bean。

有没有什么办法让Web应用程序启动时初始化JSF bean?

回答

14

如果你的代码调用FacesContext,它不会与JSF请求生命周期相关的线程之外工作。为每个请求创建一个FacesContext对象,并将其放置在请求的末尾。您可以通过static call获取它的原因是因为它在请求开始时设置为ThreadLocal。 FacesContext的生命周期与ServletContext的生命周期没有关系。

也许这还不够(听起来你已经走下了这条路),但是你应该可以使用ServletContextListener来做你想做的事。只要确保任何对FacesContext的调用都保存在JSP的请求线程中。

的web.xml:

<listener> 
    <listener-class>appobj.MyApplicationContextListener</listener-class> 
</listener> 

实现:

public class MyApplicationContextListener implements ServletContextListener { 

    private static final String FOO = "foo"; 

    public void contextInitialized(ServletContextEvent event) { 
     MyObject myObject = new MyObject(); 
     event.getServletContext().setAttribute(FOO, myObject); 
    } 

    public void contextDestroyed(ServletContextEvent event) { 
     MyObject myObject = (MyObject) event.getServletContext().getAttribute(
       FOO); 
     try { 
      event.getServletContext().removeAttribute(FOO); 
     } finally { 
      myObject.dispose(); 
     } 
    } 

} 

您可以通过JSF应用范围(如果没有其他变量具有相同名称的存在,或直接)解决这个对象:

<f:view> 
    <h:outputText value="#{applicationScope.foo.value}" /> 
    <h:outputText value="#{foo.value}" /> 
</f:view> 

如果您希望检索JSF托管bean中的对象,您可以从ExternalContext

FacesContext.getCurrentInstance() 
      .getExternalContext().getApplicationMap().get("foo"); 
+0

这最终解决了 - 我错过了“setAttribute”位,使它可以在JSF代码中访问。谢谢! – 2008-12-01 16:44:11

0

使用侦听或时加载的启动,试试这个:http://www.thoughtsabout.net/blog/archives/000033.html

+0

我以前使用过这个技巧,但它不适用于ServletContextListener,因为您没有针对 facesContext = contextFactory的请求/响应。getFacesContext(servletContext,request,response,lifecycle); 如果任何参数为null,则失败。 load-on-startup/init存在同样的问题。 – 2008-11-24 19:47:31

+0

我可能是最好/更容易创建你的类在启动和存储它。然后,当第一次访问jsf bean时,它将检查该类,并使用它或将数据从一个复制到另一个。 – Loki 2008-11-25 22:45:32

0

在JSF 2+可以使用SystemEventListener来处理它。您可以将其设置为在PostConstructApplicationEvent上对其执行初始化操作。

<system-event-listener> 
    <system-event-listener-class> 
    listeners.SystemEventListenerImpl 
    </system-event-listener-class> 
    <system-event-class> 
    javax.faces.event.PostConstructApplicationEvent 
    </system-event-class>      
</system-event-listener> 

实施看起来是这样的:

public class SystemEventListenerImpl implements SystemEventListener { 

    @Override 
    public void processEvent(SystemEvent event) throws AbortProcessingException { 
    Application application = (Application) event.getSource(); 
    //TODO 
    } 

    @Override 
    public boolean isListenerForSource(Object source) { 
    return (source instanceof Application); 
    } 
} 

这将允许你做的不仅仅是简单的传值更。