java-ee - que - primefaces managed bean example
JSF Request Scoped Beans sigue recreando nuevos beans Stateful Session en cada solicitud. (2)
Estoy construyendo mi primera aplicación Java EE usando JSF, PrimeFaces, Glassfish y Netbeans. Como soy nuevo, es posible que me esté equivocando al problema central.
Problema principal: quiero mantener la información del usuario de forma segura. Parece que hay ideas contradictorias sobre si se debe mantener en un bean de sesión de JSF o en un EJB de sesión con estado. Intento usar una sesión con estado EJB porque es más segura de esa manera.
El problema es que parece que mi aplicación está creando varias instancias de ese bean cuando espero que cree una y la vuelva a usar. Si actualizo la página, ejecuta @PostConstruct
y @PostActivate
3 veces, todas ellas con instancias diferentes. Entonces todos se destruyen cuando vuelvo a implementar la aplicación.
¿Entendí mal cómo debería funcionar o algo está configurado incorrectamente?
Trataré de mostrar una muestra de código recortado:
basic.xhtml
:
<?xml version=''1.0'' encoding=''UTF-8'' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:c="http://java.sun.com/jsp/jstl/core">
<h:head>
<title>Facelet Title</title>
</h:head>
<h:body>
Hello from Facelets
<c:if test="#{loginController.authenticated}">
Authenticated
</c:if>
<c:if test="#{loginController.authenticated}">
Authenticated
</c:if>
<c:if test="#{loginController.authenticated}">
Authenticated
</c:if>
</h:body>
</html>
LoginController
:
@Named(value = "loginController")
@RequestScoped
public class LoginController implements Serializable {
@EJB
private UserBeanLocal userBean;
public boolean isAuthenticated() {
return userBean.isAuthenticated();
}
}
UserBean
(excluyendo la interfaz UserBeanLocal
)
@Stateful
public class UserBean implements UserBeanLocal, Serializable {
boolean authenticated = false;
@PostConstruct
@PostActivate
public void setup(){
System.out.println("##### Create user Bean: "+this.toString());
}
@Override
public boolean isAuthenticated() {
System.out.println("########## Authentication test is automatically passing.");
authenticated = true;//hard coded for simplicity.
return authenticated;
}
@PrePassivate
@PreDestroy
public void cleanup(){
System.out.println("##### Destroy user Bean");
}
}
Finalmente, aquí está la salida de Glassfish después de refrescarse tres veces:
INFO: ##### Create user Bean: boundary._UserBean_Serializable@2e644784
INFO: ########## Authentication test is automatically passing.
INFO: ########## Authentication test is automatically passing.
INFO: ########## Authentication test is automatically passing.
INFO: ##### Create user Bean: boundary._UserBean_Serializable@691ae9e7
INFO: ########## Authentication test is automatically passing.
INFO: ########## Authentication test is automatically passing.
INFO: ########## Authentication test is automatically passing.
INFO: ##### Create user Bean: boundary._UserBean_Serializable@391115ac
INFO: ########## Authentication test is automatically passing.
INFO: ########## Authentication test is automatically passing.
INFO: ########## Authentication test is automatically passing.
Los beans de sesión con estado (SFSB) no son exactamente lo que usted cree que son. Parece que piensas que se comportan de alguna manera como los beans administrados por JSF en la sesión. Esto no es cierto. El término "sesión" en EJB tiene un significado completamente diferente al de la sesión HTTP que tenías en mente.
La "sesión" en EJB debe interpretarse en contexto transaccional. La transacción (básicamente, la sesión DB) vive en el caso de SFSB mientras el cliente viva. El cliente de SFSB está en su ejemplo particular, no en el navegador web, pero la JSF gestionó la propia instancia de bean, exactamente aquella en la que se ha inyectado el SFSB. Como ha puesto el bean gestionado JSF en el alcance de la solicitud, se volverá a crear el SFSB en cada solicitud HTTP junto con el bean gestionado JSF.
Como ejemplo, intente poner el bean gestionado JSF en el alcance de la vista. El ámbito de vista es útil para un formulario de pasos múltiples en la misma página, por ejemplo. Cada vez que la vista se devuelva a sí misma, se reutilizará la misma instancia de bean administrada por JSF y esta instancia le da acceso a la misma instancia de SFSB que cuando se creó el bean, que no se comparte en ningún otro lugar. La transacción SFSB permanece mientras el cliente (la vista tiene el alcance del bean gestionado por JSF) viva.
Un bean de sesión sin estado (SLSB) se puede compartir en otro lugar, pero eso no debería importar, ya que está diseñado para ser tratado como sin estado de todos modos. Esta "característica" guarda el tiempo y la memoria del contenedor para crearlos y almacenarlos. El contenedor solo puede tener un grupo de ellos. Aún más, la instancia de SLSB que se ha inyectado en una vista, sesión o bean administrado JSF con ámbito de aplicación no necesariamente necesita referir exactamente la misma instancia en cada solicitud HTTP que durante la creación de bean administrado por JSF. Incluso puede ser una instancia completamente diferente, dependiendo de las instancias disponibles en el conjunto del contenedor. La transacción vive (de forma predeterminada) siempre que un único método llame al SLSB.
Dicho esto, un SFSB no es adecuado para su caso particular de "recordar un usuario conectado". Que es "más seguro" realmente no tiene sentido. Simplemente coloque el bean gestionado JSF en el ámbito de la sesión y permita que recuerde al usuario conectado por sí mismo y haga uso de SLSB para realizar cualquier acción comercial (como interactuar con el DB) y use SFSB solo cuando desee un estado real session bean (supongo que ahora entiendes qué son exactamente :)).
Ver también:
Por lo que entiendo por mi investigación y uso, EJB SFSB no es útil para aplicaciones web ya que JSF, Spring proporciona una anotación helfull para mantener la sesión por usuario. Pero en caso de que se esté ejecutando la aplicación requerida de invocación de llamadas al servicio web y al método RPC, se necesita EJB SFSB para mantener la sesión (transelación) por usuario.