event - f viewaction jsf
Inyectar bean con ámbito de aplicación no serializable como propiedad administrada de bean con ámbito de sesión serializable en un clúster (1)
Tengo los siguientes beans administrados:
@ApplicationScoped
public class ApplicationBean {
// ...
}
@SessionScoped
public class SessionBean implements Serializable {
@ManagedProperty("#{applicationBean}")
private ApplicationBean applicationBean;
// ...
}
Esto se implementa en un clúster de servidores con varios nodos. ¿Qué sucederá cuando la sesión HTTP se serialice en otro nodo?
ApplicationBean
no está serializado porque no implementa Serializable
. ¿Será reinyectado por @ManagedProperty
? ¿O se serializará de alguna manera?
¿Qué sucederá cuando la sesión HTTP se serialice en otro nodo?
Todos los atributos de la sesión HTTP también se serializarán, incluidos los beans gestionados de JSF de ámbito de sesión. Cualquier propiedad de frijol que no sea serializable será omitida. Durante la deserialización en otro nodo, se encontrará con una NotSerializableException
en todas las propiedades de bean que no son serializables. Marcar el transient
la propiedad arreglará esa excepción, pero la propiedad seguirá siendo null
después de la deserialización.
¿Será reinyectado por @ManagedProperty? ¿O se serializará de alguna manera?
Nop. No será reinyectado. Debe hacerse cargo de esto manualmente en el caso de @ManagedProperty
.
Una forma un tanto ingenua y propensa a errores es deshacerse de @ManagedProperty
y realizar la carga diferida en el getter (por lo tanto, actúe como un proxy):
private transient ApplicationBean applicationBean;
public ApplicationBean getApplicationBean() {
if (applicationBean == null) {
FacesContext context = FacesContext.getCurrentInstance();
applicationBean = context.getApplication().evaluateExpressionGet(context, "#{applicationBean}", ApplicationBean.class);
}
return applicationBean;
}
y use el getter en todo el código, en lugar de hacer referencia directamente a la propiedad.
La mejor manera es convertirlo en un bean gestionado EJB o CDI. Se crean e inyectan de forma completamente transparente como proxies serializables y nunca tendrá que preocuparse por la serialización en ellos.
Por lo tanto, hazlo un EJB:
import javax.ejb.Singleton;
@Singleton
public class ApplicationBean {
// ...
}
import javax.ejb.EJB;
import.javax.faces.bean.ManagedBean;
import.javax.faces.bean.SessionScoped;
@ManagedBean
@SessionScoped
public class SessionBean implements Serializable {
@EJB
private ApplicationBean applicationBean;
// ... (no setter/getter necessary!)
}
O bien, conviértalos en frijoles administrados por CDI:
import javax.enterprise.context.ApplicationScoped;
import javax.inject.Named;
@Named
@ApplicationScoped
public class ApplicationBean {
// ...
}
import javax.enterprise.context.SessionScoped;
import javax.inject.Inject;
import javax.inject.Named;
@Named
@SessionScoped
public class SessionBean implements Serializable {
@Inject
private ApplicationBean applicationBean;
// ... (also here, no setter/getter necessary!)
}