tutorial sesiones que mvc faces example español ejemplo componentes bean jsf initialization startup managed-bean

jsf - sesiones - managed bean que es



¿Cómo obligo a un bean con ámbito de aplicación a crear instancias al inicio de la aplicación? (4)

Parece que no puedo encontrar la manera de forzar que un bean administrado con el objetivo de la aplicación se cree una instancia / inicialice cuando se inicia la aplicación web. Parece que los beans con ámbito de aplicación obtienen instantáneas perezosas la primera vez que se accede al bean, no cuando se inicia la aplicación web. Para mi aplicación web, esto sucede cuando el primer usuario abre una página en la aplicación web por primera vez.

La razón por la que deseo evitar esto es porque suceden varias operaciones de base de datos que consumen mucho tiempo durante la inicialización de mi bean con ámbito de aplicación. Tiene que recuperar un montón de datos del almacenamiento persistente y luego almacenar en caché algunos de los que se mostrarán con frecuencia al usuario en forma de elementos ListItem, etc. No quiero que todo eso suceda cuando el primer usuario se conecta y por lo tanto causa una larga demora

Lo primero que pensé fue utilizar un método ServletContextListener contextInitialized () de estilo antiguo y, a partir de allí, utilizar un ELResolver para solicitar manualmente la instancia de mi bean administrado (forzando así la inicialización). Lamentablemente, no puedo usar un ELResolver para activar la inicialización en esta etapa porque ELResolver necesita un FacesContext y el FacesContext solo existe durante la vigencia de una solicitud.

¿Alguien sabe de una manera alternativa de lograr esto?

Estoy utilizando MyFaces 1.2 como la implementación de JSF y no puedo actualizar a 2.x en este momento.


Lo primero que pensé fue utilizar un método ServletContextListener contextInitialized () de estilo antiguo y, a partir de allí, utilizar un ELResolver para solicitar manualmente la instancia de mi bean administrado (forzando así la inicialización). Lamentablemente, no puedo usar un ELResolver para activar la inicialización en esta etapa porque ELResolver necesita un FacesContext y el FacesContext solo existe durante la vigencia de una solicitud.

No necesita ser tan complicado. Simplemente crea una instancia del bean y colócalo en el ámbito de la aplicación con el mismo nombre de bean administrado que la clave. JSF solo reutilizará el bean cuando ya esté presente en el alcance. Con JSF encima de Servlet API, ServletContext representa el ámbito de la aplicación (ya que HttpSession representa el ámbito de la sesión y HttpServletRequest representa el ámbito de la solicitud, cada uno con los setAttribute() y getAttribute() ).

Esto debería hacer,

public void contextInitialized(ServletContextEvent event) { event.getServletContext().setAttribute("bean", new Bean()); }

donde "bean" debe ser el mismo que el <managed-bean-name> de bean con ámbito de la aplicación en faces-config.xml .

Solo para el registro, en JSF 2.x todo lo que necesita hacer es agregar eager=true a @ManagedBean en un bean @ApplicationScoped .

@ManagedBean(eager=true) @ApplicationScoped public class Bean { // ... }

Luego se auto-instanciará al inicio de la aplicación.

O bien, cuando administre respaldos de CDI @Named , tome OmniFaces @Eager :

@Named @Eager @ApplicationScoped public class Bean { // ... }


Además de la respuesta anterior de BalusC, puede usar @Startup y @Singleton (CDI), por ej.

//@Named // javax.inject.Named: only needed for UI publishing //@Eager // org.omnifaces.cdi.Eager: seems non-standard like taken @Startup below @Startup // javax.ejb.Startup: like Eager, but more standard @Singleton // javax.ejb.Singleton: maybe not needed if Startup is there //@Singleton( name = "myBean" ) // useful for providing it with a defined name @ApplicationScoped public class Bean { // ... }

lo cual está muy bien explicado here . Funciona en JPA 2.1 al menos.


Hasta donde yo sé, no se puede obligar a un bean administrado a ser instanciado al inicio de la aplicación.

¿Tal vez podría usar un ServletContextListener que, en lugar de crear instancias de su bean administrado, realizará todas las operaciones de la base de datos?

Otra solución podría ser crear instancias de su bean manualmente al inicio de la aplicación, y luego establecer el bean como un atributo de su ServletContext.

Aquí hay una muestra de código:

public class MyServletListener extends ServletContextListener { public void contextInitialized(ServletContextEvent sce) { ServletContext ctx = sce.getServletContext(); MyManagedBean myBean = new MyManagedBean(); ctx.setAttribute("myManagedBean", myManagedBean); } }

En mi opinión, esto está lejos de ser un código limpio, pero parece que funciona bien.


Romain Manni-Bucau publicó una solución clara para esto que usa CDI 1.1 en su blog .

El truco es dejar que Bean observe la inicialización de los ámbitos del ciclo de vida integrado, es decir, ApplicationScoped en este caso. Esto también se puede usar para la limpieza del cierre. Entonces un ejemplo se ve así:

@ApplicationScoped public class ApplicationScopedStartupInitializedBean { public void init( @Observes @Initialized( ApplicationScoped.class ) Object init ) { // perform some initialization logic } public void destroy( @Observes @Destroyed( ApplicationScoped.class ) Object init ) { // perform some shutdown logic } }