JSF инициализирует область приложения bean при инициализации контекста
Я создаю веб-приложение JSF + Facelets, одним из которых является метод, который так часто сканирует каталог и индексирует любые изменения. Этот метод является частью bean, который находится в области приложения. Я создал подкласс TimerTask для вызова метода каждые X миллисекунд. Моя проблема заключается в инициализации bean. Я могу ссылаться на bean на странице, и когда я иду на страницу, bean инициализируется и работает по назначению; вместо этого я хотел бы инициализировать bean, когда веб-контекст инициализирован, так что для запуска метода индексирования не требуется посещать страницу. Google показал несколько людей, которые хотят эту функциональность, но никаких реальных решений вне интеграции с Spring, которые я действительно не хочу делать, чтобы получить эту функциональность.
Я пробовал играть с обоими сервлетами, у которых есть "load-on-startup", и ServletContextListener, чтобы все было в порядке, и не смог получить правильную настройку, либо потому, t Доступен FacesContext, или потому, что я не могу ссылаться на bean из среды JSF.
Есть ли способ получить JSF bean, инициализированный при запуске веб-приложения?
Ответы
Ответ 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");
Ответ 2
Используя прослушиватели или загрузку при запуске, попробуйте следующее: http://www.thoughtsabout.net/blog/archives/000033.html
Ответ 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);
}
}
Это позволит вам сделать намного больше, чем просто передать значение.