Java JSF 在上下文初始化时初始化应用程序范围的 bean

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/315073/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 13:03:32  来源:igfitidea点击:

JSF initialize application-scope bean when context initialized

javajsf

提问by Matt McMinn

I'm building a JSF+Facelets web app, one piece of which is a method that scans a directory every so often and indexes any changes. This method is part of a bean which is in application scope. I have built a subclass of TimerTask to call the method every X milliseconds. My problem is getting the bean initialized. I can reference the bean on a page, and when I go to the page, the bean is initialized, and works as directed; what I would like instead is for the bean to be initialized when the web context is initialized, so that it doesn't require a page visit to start the indexing method. Google has shown a few people that want this functionality, but no real solutions outside of integrating with Spring, which I really don't want to do just to get this piece of functionality.

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

I've tried playing around with both the servlets that have "load-on-startup" set, and a ServletContextListener to get things going, and haven't been able to get the set up right, either because there isn't a FacesContext available, or because I can't reference the bean from the JSF environment.

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

Is there any way to get a JSF bean initialized on web app startup?

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

采纳答案by McDowell

If your code calls FacesContext, it will not work outside a thread associated with a JSF request lifecycle. A FacesContext object is created for every request and disposed at the end of the request. The reason you can fetch it via a static callis because it is set to a ThreadLocalat the start of the request. The lifecycle of a FacesContext bears no relation to that of a ServletContext.

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

Maybe this isn't enough (it sounds like you've already been down this route), but you should be able to use a ServletContextListener to do what you want. Just make sure that any calls to the FacesContext are kept in the JSP's request thread.

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

web.xml:

网页.xml:

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

Implementation:

执行:

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();
        }
    }

}

You can address this object via the JSF application scope (or just directly if no other variable exists with the same name):

您可以通过 JSF 应用程序范围(或者如果不存在其他同名变量,则直接访问):

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

If you wish to retrieve the object in a JSF managed bean, you can get it from the ExternalContext:

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

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

回答by Loki

Using listeners or load-on-startup, try this: http://www.thoughtsabout.net/blog/archives/000033.html

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

回答by John Yeary

In JSF 2+ you can use a SystemEventListenerto handle it. You would set it to take action on the PostConstructApplicationEventto initialize it.

在 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>

The implementation would look something like :

实现看起来像:

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);
  }
}

This will allow you to do a lot more than just simply passing a value.

这将允许您做的不仅仅是简单地传递一个值。