2012-05-16 9 views
7

Estoy usando Spring y JSF 2 para crear una aplicación web. Los objetos de negocio se mantienen en el recipiente de la primavera, y les inyectan en los beans gestionados mediante el @ManagedProperty, así:¿Cómo volver a inyectar un @ManagedProperty transitorio en la deserialización?

@ManagedBean 
@ViewScoped 
public class SomeMB implements Serializable { 
    private static final long serialVersionUID = 1L; 

    @Getter @Setter 
    @ManagedProperty("#{someService}") 
    private SomeService someService; 
    // ... 

El problema es, me siguen dando un NotSerializableException para una clase de primavera (ServiceLocatorFactoryBean) que está siendo utilizado por el SomeService bean.

Si lo hago transient, ¿cómo podría hacer la reinyección después de la deserialización?

O, ¿cuáles serían otras formas de resolver este problema?

He estado leyendo varias otras preguntas similares aquí, pero no he encontrado ninguna que tratara exactamente con este problema.

+2

FYI: este problema no existe cuando solo utiliza EJB de Java EE en lugar de Spring. – BalusC

+0

@BalusC Sí, leí sobre eso en otras preguntas, lamentablemente aún no sé lo suficiente sobre EJB para usarlo (y no sé si podría convencer a los compañeros de trabajo de que me lo permitieran probar en este proyecto) . ¿Podría señalarme un buen recurso para aprender sobre esto, por cierto? – elias

+0

No es tan difícil. Solo asegúrese de que su contenedor ya sea compatible con EJB (Glassfish, JBoss, Weblogic, etc.). Anote la clase de servicio con '@ Stateless' o' @ Stateful' e inyéctela por '@ EJB'. Eso es. No se requiere getter/setter por cierto. – BalusC

Respuesta

3

En lugar de la inyección de los granos de resorte a través de EL en una @ManagedProperty anotación (ejecutado en la inicialización ManagedBean), obtener los granos que evalúan la EL en tiempo de ejecución.

Con este enfoque, esto es lo que los granos de JSF debe ser similar:

@ManagedBean 
@ViewScoped 
public class SomeMB implements Serializable { 
    private static final long serialVersionUID = 1L; 

    private static SomeService someService() { 
     return SpringJSFUtil.getBean("someService"); 
    } 
    // ... 

Y la clase de utilidad SpringJSFUtil.java que recibe el grano a través de EL:

import javax.faces.context.FacesContext; 

public class SpringJSFUtil { 

    public static <T> T getBean(String beanName) { 
     if (beanName == null) { 
      return null; 
     } 
     return getValue("#{" + beanName + "}"); 
    } 

    @SuppressWarnings("unchecked") 
    private static <T> T getValue(String expression) { 
     FacesContext context = FacesContext.getCurrentInstance(); 
     return (T) context.getApplication().evaluateExpressionGet(context, 
       expression, Object.class); 
    } 
} 

Esto elimina la propiedad Spring Bean (a costa de hacer algunas evaluaciones EL), evitando así todos los problemas de serialización de tener la propiedad en primer lugar.

El mismo enfoque, utilizando OmniFaces:

En mi código real, yo uso el método de un utility class disponible de OmniFacesevaluateExpressionGet(String expression). Por lo tanto, para aquellos de ustedes que lo usan también, esto es lo que mi código realmente se parece a:

import static org.omnifaces.util.Faces.evaluateExpressionGet; 

@ManagedBean 
@ViewScoped 
public class SomeMB implements Serializable { 
    private static final long serialVersionUID = 1L; 

    private static SomeService someService() { 
     return evaluateExpressionGet("#{someService}"); 
    } 
    // ... 

en cuenta que aquí el método obtiene el EL completa ("# {expresión}"), no sólo la primavera nombre de frijol (o obtendrías una ClassCastException).

-1

bien tener esto en cuenta en el manual de la primavera ( link to spring):

basada en Constructor o basado en colocador DI?

Dado que puede mezclar ambos, DI basado en Constructor y Setter, es una buena regla general usar argumentos de constructor para dependencias obligatorias y definidores para dependencias opcionales. Tenga en cuenta que el uso de una anotación @Required en un setter se puede usar para hacer que los setters requieran dependencias.

El equipo de Spring generalmente recomienda la inyección de setter, ya que un gran número de argumentos de constructor pueden resultar difíciles de manejar, especialmente cuando las propiedades son opcionales. Los métodos Setter también hacen que los objetos de esa clase sean susceptibles de reconfiguración o reinyección más adelante. La administración a través de JMX MBeans es un caso de uso convincente.

Algunos puristas prefieren la inyección basada en el constructor. El suministro de todas las dependencias de objetos significa que el objeto siempre se devuelve al código del cliente (llamadas) en un estado totalmente inicializado. La desventaja es que el objeto se vuelve menos susceptible de reconfiguración y reinyección.

Use la DI que tenga más sentido para una clase en particular. A veces, cuando se trata de clases de terceros para las que no tiene la fuente, la elección se hace por usted. Una clase heredada no puede exponer ningún método setter, por lo que la inyección del constructor es la única DI disponible.

+0

Disculpe, no lo estoy siguiendo ... ¿Qué tiene que ver la DI basada en el constructor versus la depuradora con mi problema? – elias

2

Pruebe @Scope (value = BeanDefinition.SCOPE_SINGLETON, proxyMode = ScopedProxyMode.INTERFACES) en su Spring @Service. Esto debería inyectar un objeto proxy serializable en su bean administrado que reubicará el servicio al acceder después de la deserialización.

0

Para los siguientes: tuve un problema similar con un ResourceBundle inyectado. El uso de parte de la respuesta de BalusC, hice lo siguiente:

@ManagedProperty(value="#{myBundle}") 
private transient ResourceBundle myBundle; 

private Object readResolve() { 
    myBundle = FacesContext.getCurrentInstance().getApplication() 
     .evaluateExpressionGet(FacesContext.getCurrentInstance(), "#{myBundle}", 
     ResourceBundle.class); 
    return this; 
} 

De esta manera, la EL se evalúa sólo cuando se deserializa el bean gestionado.

Cuestiones relacionadas