Я создаю веб-приложение JSF + Facelets, одним из которых является метод, который так часто сканирует каталог и индексирует любые изменения. Этот метод является частью компонента, который находится в области приложения. Я создал подclass TimerTask для вызова метода каждые X миллисекунд. Моя проблема заключается в том, чтобы инициализировать компонент. Я могу ссылаться на компонент на странице, и когда я иду на страницу, компонент инициализируется и работает по назначению; вместо этого я хотел бы, чтобы компонент был инициализирован при инициализации веб-контекста, так что для запуска метода индексирования не требуется посещать страницу. Google показала несколько людей, которые хотят эту функциональность, но никаких реальных решений за пределами интеграции с Spring, которые я действительно не хочу делать, чтобы получить эту функциональность.
Я пробовал играть с обоими сервлетами, на которых установлен «load-on-startup», и ServletContextListener, чтобы добиться успеха, и не смог получить правильную настройку, потому что отсутствует FacesContext ansible или потому, что я не могу ссылаться на компонент из среды JSF.
Есть ли способ получить JSF-компонент, инициализированный при запуске веб-приложения?
Если ваш код вызывает FacesContext , он не будет работать за пределами streamа, связанного с жизненным циклом запроса JSF. Объект FacesContext создается для каждого запроса и размещается в конце запроса. Причина, по которой вы можете получить его через статический вызов, состоит в том, что он установлен в ThreadLocal в начале запроса. Жизненный цикл FacesContext не имеет отношения к циклу ServletContext.
Возможно, этого недостаточно (похоже, что вы уже на этом пути), но вы должны иметь возможность использовать ServletContextListener, чтобы делать то, что вы хотите. Просто убедитесь, что любые обращения к FacesContext хранятся в streamе запросов JSP.
web.xml:
appobj.MyApplicationContextListener
Реализация:
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 (или просто напрямую, если никакая другая переменная не существует с тем же именем):
Если вы хотите получить объект в управляемом компоненте JSF, вы можете получить его из ExternalContext :
FacesContext.getCurrentInstance() .getExternalContext().getApplicationMap().get("foo");
Используя прослушиватели или загрузку при запуске, попробуйте следующее: http://www.thoughtsabout.net/blog/archives/000033.html
В JSF 2+ вы можете использовать SystemEventListener
для его обработки. Вы должны установить его для принятия решения в PostConstructApplicationEvent
для его инициализации.
listeners.SystemEventListenerImpl javax.faces.event.PostConstructApplicationEvent
Реализация будет выглядеть примерно так:
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); } }
Это позволит вам сделать намного больше, чем просто передать значение.