Tengo dos instancias de un beans CDI SessionScoped para la misma sesión. Tenía la impresión de que el CDI generaría una instancia para mí, pero generó dos. ¿Entiendo mal cómo funciona el CDI, o encontré un error?CDI SessionScoped Bean resultados en dos instancias en la misma sesión
Aquí está el código de frijol:
package org.mycompany.myproject.session;
import java.io.Serializable;
import javax.enterprise.context.SessionScoped;
import javax.faces.context.FacesContext;
import javax.inject.Named;
import javax.servlet.http.HttpSession;
@Named @SessionScoped public class MyBean implements Serializable {
private String myField = null;
public MyBean() {
System.out.println("MyBean constructor called");
FacesContext fc = FacesContext.getCurrentInstance();
HttpSession session = (HttpSession)fc.getExternalContext().getSession(false);
String sessionId = session.getId();
System.out.println("Session ID: " + sessionId);
}
public String getMyField() {
return myField;
}
public void setMyField(String myField) {
this.myField = myField;
}
}
Este es el código Facelet:
<?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:f="http://java.sun.com/jsf/core">
<f:view contentType="text/html" encoding="UTF-8">
<h:head>
<title>Test</title>
</h:head>
<h:body>
<h:form id="form">
<h:inputText value="#{myBean.myField}"/>
<h:commandButton value="Submit"/>
</h:form>
</h:body>
</f:view>
</html>
Aquí está la salida de despliegue y navegar a la página:
INFO: Loading application org.mycompany_myproject_war_1.0-SNAPSHOT at /myproject
INFO: org.mycompany_myproject_war_1.0-SNAPSHOT was successfully deployed in 8,237 milliseconds.
INFO: MyBean constructor called
INFO: Session ID: 175355b0e10fe1d0778238bf4634
INFO: MyBean constructor called
INFO: Session ID: 175355b0e10fe1d0778238bf4634
El uso de GlassFish 3.0.1
realidad estaba alertado al problema anterior por un relacionados uno: llamar a un método no final en un constructor (o bloque inicializador) provoca efectos no deseados con CDI. Desde entonces he leído que no se recomienda utilizar un método que no sea final (http://download.oracle.com/javase/tutorial/java/javaOO/initial.html). Si utilizo un método no final para inicializar una lista en un bean CDI, ¡el inicializador se llama dos veces! Nota: CDI no permite los métodos finales y arrojará una Excepción de tiempo de ejecución que indique que el bean no es proxyable. La "solución" es no llamar al método no final y hacer todo el trabajo en el bloque del iniciador. – Ryan
Me he dado cuenta de que si defino un método init anotado con @PostConstruct, solo se llama una vez (a pesar de dos instancias del bean que se está creando). Supongo que CDI está creando un grupo de instancias de mi bean y llama a la construcción de post ya que los saca del grupo. Supongo que asociar la instancia del bean que aún está en el grupo con la sesión HTTP actual no tiene sentido. – Ryan
Vea mi respuesta más abajo. Las 2 instancias 1ª es la instancia contextual, 2ª es el proxy. Por supuesto, el @PostConstruct solo se llamará para la instancia contextual y _no_ para el proxy. – struberg