Подтвердить что ты не робот

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

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

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

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

4b9b3361

Ответ 1

Если ваш код вызывает 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 bean, вы можете получить его из ExternalContext:

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

Ответ 3

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

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