16

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

我已经尝试使用设置了“启动时加载”的 servlet 和 ServletContextListener 来让事情顺利进行,但由于没有 FacesContext,因此无法正确设置可用,或者因为我无法从 JSF 环境中引用 bean。

有什么方法可以在 Web 应用程序启动时初始化 JSF bean?

4

3 回答 3

15

如果您的代码调用FacesContext,它将无法在与 JSF 请求生命周期关联的线程之外工作。为每个请求创建一个 FacesContext 对象,并在请求结束时处理。您可以通过静态调用获取它的原因是因为它在请求开始时设置为ThreadLocal。FacesContext 的生命周期与 ServletContext 的生命周期无关。

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

网页.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");
于 2008-11-27T00:29:30.493 回答
0

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

于 2008-11-24T19:35:40.710 回答
0

在 JSF 2+ 中,您可以使用 aSystemEventListener来处理它。您可以将其设置为对 执行操作以对其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);
  }
}

这将允许您做更多的事情,而不仅仅是简单地传递一个值。

于 2012-07-13T19:10:10.977 回答