jsf-2 - mvc - usando jsf
¿Cuándo crea JSF una sesión y qué pone en un mapa de sesión? (1)
¿Cuándo crea JSF una sesión?
La forma más sencilla de solucionar esto es crear un HttpSessionListener
, colocar un punto de interrupción de depuración en el método sessionCreated()
e inspeccionar la pila de llamadas que necesitaba obtener la sesión por primera vez (y, por lo tanto, implícitamente necesita crearla).
En el siguiente ejemplo, verá una cadena de llamadas getSession()
en la pila de llamadas. Verá que el método FaceletViewHandlingStrategy.renderView()
es el que lo llama por primera vez.
Después de hacer clic en la línea FaceletViewHandlingStrategy.renderView()
en la pila de llamadas del depurador, accederá a su código fuente (Maven cargará el código fuente automáticamente, de lo contrario, deberá adjuntarlo manualmente).
Verá, cuando el ahorro de estado del lado del servidor está habilitado y la vista para procesar no es transitoria ( sin estado ), JSF creará la sesión implícitamente, solo para asegurarse de que se creó a tiempo para guardar la vista (si la sesión se creó más tarde) , por ejemplo, durante la fase de respuesta al renderizado, de lo contrario arriesgarías excepciones como esta. Agregar <h: form> hace que java.lang.IllegalStateException: No se puede crear una sesión después de que se haya confirmado la respuesta ).
También en el código fuente verá inmediatamente que cuando el método de ahorro de estado se establece en cliente, o cuando la vista es sin estado como en <f:view transient="true">
, entonces JSF ya no creará implícitamente la sesión . Las versiones anteriores de JSF pueden hacer eso tal como se imaginaba, pero esto se debe considerar como un error y se debe corregir en una versión más nueva.
Si desea garantizar la apatridia y evitar la creación de sesiones accidentales / imprevistas, puede throw new IllegalStateException()
dentro del método sessionCreated()
. Cuando eso sucede, solo tienes que mirar en la pila de llamadas quién es responsable de crear la sesión y luego corregir / cambiar el código para que ya no lo haga.
¿Qué pone en un mapa de sesión?
Bajo las cubiertas, ExternalContext#getSessionMap()
delega en HttpSession#setAttribute()
/ getAttribute()
/ removeAttribute()
. Puede escuchar esos métodos usando un HttpSessionAttributeListener
.
En el siguiente ejemplo, verá que la línea ViewScopeContextManager.getContextMap()
llama al SessionMap#put()
para colocar algo en el mapa de la sesión. Cuando despliegue el argumento del event
, verá el nombre y el valor del atributo de la sesión, que es com.sun.faces.application.view.activeViewContexts
y un ConcurrentHashMap
vacío, respectivamente.
De hecho, estaba usando un @Named @ViewScoped
que se hizo referencia mediante una expresión de valor en la página en particular (verá EL resolver y Weld resolver más abajo en la pila de llamadas). Al hacer clic en la línea ViewScopeContextManager.getContextMap()
en la pila de llamadas, verá que solo estaba preparando un mapa en el ámbito de la sesión para poder almacenar los beans de ámbito de la vista.
Ese es solo un ejemplo. Hay más cosas que podrían almacenarse en la sesión. Usar un depurador de esta manera e inspeccionar el código fuente asociado dirá mucho sobre el Por qué .
Estoy ejecutando Mojarra 2.2.0.
<context-param>
<param-name>javax.faces.STATE_SAVING_METHOD</param-name>
<param-value>client</param-value>
</context-param>
El método de acción del frijol administrado es-
public void action() {
HttpSession session = (HttpSession) FacesContext.getCurrentInstance()
.getExternalContext().getSession(false);
System.out.println(session.getId()); // not null for stateful views
}
Para vistas stateless
, session.getId()
arroja NPE
Para las vistas que no son apátridas: disparando una solicitud GET, hay JSESSIONID=340041C96D5AA446D761C3602F54A76D
Lo leí aquí que-
Para el mecanismo de ahorro del estado del lado del cliente, JSF no creará la sesión y almacenará el estado de la vista en un campo de entrada oculto con el nombre javax.faces.ViewState en el formulario siempre que sea necesario.
Además, se menciona aquí que
De hecho, JSF autocreará la sesión porque el estado de la vista JSF debe almacenarse allí. Si configura el método de ahorro de estado JSF para el cliente en lugar del servidor, no se almacenará en sesión y, por lo tanto, no es necesario crear una sesión.
Creo que la línea anterior es fuente de problemas para mí.
Si configura el método de ahorro de estado JSF para el cliente en lugar del servidor, entonces no se almacenará en la sesión // TOTALMENTE ACORDADO
y
por lo tanto, no es necesario crear una sesión. // Esto confunde porque para el mecanismo de ahorro del lado del cliente, el contenedor del servlet genera una identificación de sesión y, por lo tanto, hay una sesión asociada a la solicitud.
En referencia a la discusión que tuve con BalusC en esta pregunta , creé un HttpSessionListener-
@WebListener
public class MyHttpSessionListener implements HttpSessionListener {
public void sessionCreated(HttpSessionEvent event) {
Thread.dumpStack();
}
public void sessionDestroyed(HttpSessionEvent event) {
}
}
Vea a continuación las capturas de pantalla adjuntas (estas 2 capturas de pantalla son para la versión 2.0.3, debe haber un error antiguo debido al cual se creó la sesión) -