mvc - El método JSF 2.1 ViewScopedBean @PreDestroy no se llama
jsf tutorial español (2)
Tengo un método en una vista de Bean con @PreDestroy
con la anotación @PreDestroy
y otro con la anotación @PostConstruct
.
El método @PostConstruct
se llama correctamente cada vez que navego a la página que utiliza esta vista de bean con ámbito.
Sin embargo, cuando navego a una página nueva (que no utiliza este Bean de alcance de vista) por <h:link/>
, nunca se llama al método @PreDestroy
.
No estoy hablando de cambiar manualmente la url o el final de la sesión , solo de un caso de navegación.
Lo que me estoy perdiendo?
Gracias por adelantado
He preparado un pequeño proyecto de NetBeans que demuestra cuándo JSF2.2 CDI-compatible @ViewScoped beans (javax.faces.view.ViewScoped) se libera para la recolección de basura en diferentes casos de navegación (para Mojarra 2.2.9, Glassfish4, NetBeans8.0.2, JDK1 .7), disponible para descargar aquí . El código se omite aquí, ve esa descarga.
Los casos de navegación manejados y los resultados se resumen en esta imagen:
Para supervisar los beans @ViewScoped, use VisualVM contra Glassfish (o el perfilador de NetBeans incorporado en el mini proyecto) y filtre la vista de clase del histograma Heap de la memoria Sampler en el nombre del paquete ''webel.com.jsf''. La siguiente imagen muestra 66 instancias absurdas de webel.com.jsf.Jsf22ViewBean después de una copiosa experimentación con h: link, GET de URL del navegador y GET de RELOAD en el navegador, cuyas instancias no serán basura (que puede probar usando VisualVM Perform GC botón):
En comparación, navegando desde el index.xhtml (que usa el bean @ViewScoped una vez para una lectura sencilla de la variable EL) hasta done.xhtml (que no usa el bean) usando h: commandButton y una expresión del método de acción o un los resultados de la cadena de acción en el bean @ViewScoped que se lanza para la recolección de basura (siempre hay una referencia del WeldClientProxy a un bean @ViewScoped, y mientras navega hacia adelante y hacia atrás usando h: commandButton, WeldClientProxy pasa de un bean liberable al siguiente) .
Esto es por diseño. Solo se destruirá inmediatamente cuando una acción POST genere una navegación que no sea una devolución de datos a la misma vista (es decir, el método de acción no devuelve null
o void
, sino una String
completo, incluso cuando esté vacío).
El <h:link>
genera un enlace GET que no invoca ninguna acción POST. Como no es confiablemente posible notificar al lado del servidor mediante una solicitud HTTP (XML) cuando la vista está descargada, no se puede notificar a JSF que destruya el bean con ámbito de vista asociado con la vista. En tal caso, el bean con ámbito de vista solo se destruirá cuando expire la sesión o cuando se excedan las vistas lógicas máximas en sesión (el valor predeterminado es 15) y la vista asociada es la primera en orden.
Si realmente desea desdoblar la vista del bean con ámbito mediante una acción de navegación, entonces su mejor opción es hacer una solicitud POST con <h:commandLink>
y emitir una redirección devolviendo el resultado de navegación con ?faces-redirect=true
parameter . Pero después de todo esto no es amigable con los motores de búsqueda, ya que los bots no indexarán los enlaces POST.
Después de todo, no me importaría que la vista aún esté en la sesión. Si tiene la intención de hacer algo de limpieza o registro, buscaría formas alternativas, dependiendo del requisito funcional concreto.
En teoría , sería posible mediante el evento HTML DOM antes de la onbeforeunload
, pero este es un evento no estándar y el comportamiento del navegador no está especificado en cuanto a qué sucede cuando envía una solicitud ajax durante ese evento. A veces llegará, pero a veces tampoco. Actualización : en la práctica , esto se ha implementado en OmniFaces @ViewScoped
desde OmniFaces 2.2 con ayuda de XHR síncrono y funciona bastante bien en los principales navegadores. Desde la versión 2.3, incluso destruye físicamente el estado de la vista lateral del servidor JSF asociado.