JSF инициализирует компонент области приложения, когда контекст инициализирован

Я создаю веб-приложение JSF+Facelets, одним из компонентов которого является метод, который время от времени сканирует каталог и индексирует любые изменения. Этот метод является частью компонента, который находится в области применения. Я построил подкласс TimerTask для вызова метода каждые X миллисекунд. Моя проблема в инициализации компонента. Я могу ссылаться на bean-компонент на странице, и когда я перехожу на страницу, bean-компонент инициализируется и работает в соответствии с указаниями; вместо этого я хотел бы, чтобы компонент инициализировался при инициализации веб-контекста, чтобы не требовалось посещение страницы для запуска метода индексации. Google показал нескольким людям, которые хотят эту функциональность, но не имеют никаких реальных решений, кроме интеграции с Spring, что я действительно не хочу делать, просто чтобы получить эту функциональность.

Я попытался поиграть как с сервлетами, у которых установлен параметр "загрузка при запуске", так и с ServletContextListener, чтобы добиться успеха, и не смог правильно настроить его, потому что нет FacesContext. или потому что я не могу ссылаться на bean-компонент из среды JSF.

Есть ли способ инициализировать bean-компонент JSF при запуске веб-приложения?

3 ответа

Решение

Если ваш код вызывает FacesContext, он не будет работать вне потока, связанного с жизненным циклом запроса JSF. Объект FacesContext создается для каждого запроса и располагается в конце запроса. Причина, по которой вы можете получить его через статический вызов, заключается в том, что он установлен в 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, вы можете получить его из ExternalContext:

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

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

Это позволит вам сделать гораздо больше, чем просто передать значение.

Используя слушателей или загрузку при запуске, попробуйте это: http://www.thoughtsabout.net/blog/archives/000033.html

Другие вопросы по тегам