type event jsf session cluster-computing

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!) }