java - example - JSF inicializa bean de ámbito de aplicación cuando se inicializa el contexto
jsf tutorial español (3)
Usando oyentes o load-on-startup, intente esto: http://www.thoughtsabout.net/blog/archives/000033.html
Estoy construyendo una aplicación web JSF + Facelets, una de las cuales es un método que escanea un directorio de vez en cuando e indexa los cambios. Este método es parte de un bean que está dentro del alcance de la aplicación. Creé una subclase de TimerTask para llamar al método cada X milisegundos. Mi problema es inicializar el frijol. Puedo hacer referencia al bean en una página, y cuando voy a la página, el bean se inicializa y funciona como se indica; lo que me gustaría en cambio es que el bean se inicialice cuando se inicializa el contexto web, de modo que no se requiera una visita a la página para iniciar el método de indexación. Google ha mostrado a algunas personas que quieren esta funcionalidad, pero no tiene soluciones reales aparte de la integración con Spring, lo que realmente no quiero hacer solo para obtener esta funcionalidad.
He intentado jugar con los servlets que tienen el set "load-on-startup" y un ServletContextListener para poner en marcha las cosas, y no he podido obtener la configuración correcta, ya sea porque no hay un FacesContext disponible, o porque no puedo hacer referencia al bean desde el entorno JSF.
¿Hay alguna forma de obtener un bean JSF inicializado en el inicio de la aplicación web?
Si su código llama a FacesContext , no funcionará fuera de un hilo asociado con un ciclo de vida de solicitud JSF. Se crea un objeto FacesContext para cada solicitud y se elimina al final de la solicitud. La razón por la que puede obtenerlo a través de una llamada estática es porque está configurado en ThreadLocal al inicio de la solicitud. El ciclo de vida de un FacesContext no guarda relación con el de un ServletContext.
Tal vez esto no sea suficiente (parece que ya ha pasado por esta ruta), pero debería poder usar un ServletContextListener para hacer lo que quiera. Solo asegúrese de que las llamadas a FacesContext se mantengan en el hilo de solicitud de JSP.
web.xml:
<listener>
<listener-class>appobj.MyApplicationContextListener</listener-class>
</listener>
Implementación:
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();
}
}
}
Puede abordar este objeto a través del alcance de la aplicación JSF (o solo directamente si no existe otra variable con el mismo nombre):
<f:view>
<h:outputText value="#{applicationScope.foo.value}" />
<h:outputText value="#{foo.value}" />
</f:view>
Si desea recuperar el objeto en un bean gestionado JSF, puede obtenerlo del ExternalContext :
FacesContext.getCurrentInstance()
.getExternalContext().getApplicationMap().get("foo");
En JSF 2+ puedes usar un SystemEventListener
para manejarlo. PostConstructApplicationEvent
configurarlo para que tome medidas en PostConstructApplicationEvent
para inicializarlo.
<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>
La implementación sería algo así como:
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);
}
}
Esto le permitirá hacer mucho más que solo pasar un valor.