2010-07-05 14 views
43
  • un caso estándar - que tienen un controlador (@Controller) con @Scope("session").
  • clases puesto en la sesión se espera normalmente para implementar Serializable para que puedan ser almacenados físicamente en caso de que se reinicie el servidor, por ejemplo
  • Si el controlador implementa Serializable, esto significa que todos los servicios (otros granos de primavera) que es la referencia también será serializada. A menudo son proxies, con referencias a gestores de transacciones, fábricas de gestores de entidades, etc.
  • No es improbable que algún servicio, o incluso controlador, contenga una referencia al ApplicationContext, implementando ApplicationContextAware, por lo que esto puede significar que el todo el contexto está serializado. Y dado que tiene muchas conexiones, es decir, cosas que no son serializables por idea, se restaurará en estado corrupto.

Hasta ahora he ignorado estos problemas. Recientemente pensé en declarar todas mis dependencias de primavera transient y recuperarlas en readResolve() mediante las clases de utilidad estática WebApplicationContextUtils y las que mantienen la solicitud/ServletContext en un ThreadLocal. Esto es tedioso, pero garantiza que, cuando el objeto se deserialice, sus dependencias estarán "actualizadas" con el contexto de la aplicación actual.primavera ámbito de sesión (controladores) y referencias a servicios, en términos de serialización

¿Hay alguna práctica aceptada para esto o alguna guía para serializar partes del contexto de primavera?

Tenga en cuenta que en JSF, los beans administrados (~ controladores) tienen estado (a diferencia de los marcos web basados ​​en acciones). Entonces quizás mi pregunta sea más para JSF, que para spring-mvc.

Respuesta

19

En this presentation (alrededor de 1,14) la el hablante dice que este problema se resuelve en la primavera 3.0 al proporcionar un proxy de beans no serializables, que obtiene una instancia del contexto de la aplicación actual (en la deserialización)

+0

cualquier cambio para un enlace? :) – Bozho

+1

¡Lo encontraste! http://www.infoq.com/presentations/Whats-New-in-Spring-3.0 Desplácese 1 hora en la película –

+0

Genial. Explica exactamente este problema. y está resuelto. Incluso sin Configurable. Edité tu respuesta para indicar eso. – Bozho

7

Esperaría que los controladores de ámbito como 'singleton', es decir, una vez por aplicación, en lugar de en la sesión.

El alcance de sesión generalmente se usa más para almacenar información por usuario o por funciones de usuario.

Normalmente solo almaceno el objeto 'usuario' en la sesión, y tal vez algunos frijoles se utilizan para la autenticación o tal. Eso es.

Echa un vistazo a la documentación de primavera para configurar algunos datos de usuario en el ámbito de sesión, utilizando un proxy AOP:

http://static.springsource.org/spring/docs/2.5.x/reference/beans.html#beans-factory-scopes-other-injection

Espero que ayude

+0

A veces también tiene sentido tener controles de alcance. No a menudo, pero a veces. – skaffman

+0

mi suposición es que los controladores son a menudo de alcance de solicitud, ya que almacena cierta información por solicitud allí (es decir, no singleton). – Bozho

+1

Simplemente curioso, nunca he usado un controlador con alcance de sesión: ¿cuáles son algunos de los casos en los que es útil? –

2

Recientemente combiné JSF con Spring. Uso RichFaces y la característica @KeepAlive, que serializa el bean JSF que respalda la página. Hay dos maneras en que he logrado que esto funcione.

1) Uso @Component ("sesión") en el bean de respaldo JSF

2) Obtener el grano de ELContext cuando cada vez que lo necesite, algo como esto:

@SuppressWarnings("unchecked") 
public static <T> T getBean(String beanName) { 
    return (T) FacesContext.getCurrentInstance().getApplication().getELResolver().getValue(FacesContext.getCurrentInstance().getELContext(), null, beanName); 
} 
7

Parece que recompensas no atrajo una respuesta única, así que voy a documentar mi comprensión limitada:

@Configuration 
public class SpringConfig { 

    @Bean 
    @Scope(proxyMode = ScopedProxyMode.TARGET_CLASS) 
    MyService myService() { 
     return new MyService(); 
    } 

    @Bean 
    @Scope("request") 
    public IndexBean indexBean() { 
     return new IndexBean(); 
    } 

    @Bean 
    @Scope("request") 
    public DetailBean detailBean() { 
     return new DetailBean(); 
    } 
} 

public class IndexBean implements Serializable { 

    @Inject MyService myService; 

    public void doSomething() { 
     myService.sayHello(); 
    } 
} 

public class MyService { 
    public void sayHello() { 
     System.out.println("Hello World!"); 
    } 
} 

primavera entonces no inyectará el MyService desnudo en IndexBean, pero un proxy serializable a ella. (Probé eso, y funcionó).

Sin embargo, la documentación de primavera writes:

Usted no hacer necesidad de utilizar el <aop:scoped-proxy/> en conjunción con los granos cuyo ámbito como singletons o prototypes. Si intenta crear un proxy con ámbito para un bean Singleton, se genera el BeanCreationException.

Al menos cuando se usa la configuración basada en Java, el bean y su proxy se pueden instanciar muy bien, es decir, no se produce ninguna excepción. Sin embargo, parece que usar proxies con alcance para lograr la serializabilidad no es el uso previsto de dichos proxys. Por lo tanto, me temo que Spring podría solucionar ese "error" y evitar la creación de proxies con ámbito a través de la configuración basada en Java, también.

Además, existe una limitación: el nombre de clase del proxy es diferente después del reinicio de la aplicación web (porque el nombre de clase del proxy se basa en el código hash del consejo utilizado para construirlo, que a su vez depende en el hashCode del objeto de clase de un interceptor. Class.hashCode no anula Object.hashCode, que no es estable durante los reinicios). Por lo tanto, las sesiones serializadas no pueden ser utilizadas por otras máquinas virtuales ni por reinicios.

2

Después de probar todas las diferentes alternativas sugerí que todo lo que tenía que hacer era agregar aop: scoped-proxy a mi definición de bean y comenzó a funcionar.

<bean id="securityService" 
    class="xxx.customer.engagement.service.impl.SecurityContextServiceImpl"> 
    <aop:scoped-proxy/> 
    <property name="identityService" ref="identityService" /> 
</bean> 

securityService se inyecta en mi managedbean que es view scoped. Esto parece que funciona bien. Según la documentación de primavera, se supone que arrojará una BeanCreationException ya que securityService es un singleton. Sin embargo, esto no parece suceder y funciona bien. No estoy seguro de si esto es un error o cuáles serían los efectos secundarios.

+0

Aquí tuve el mismo problema y lo resolví en el mismo manera: https://stackoverflow.com/questions/9986197/jsf-managedbean-injected-properties-not-working-correctly-on-state-saving-meth – Ermal

1

Serialization de Dynamic-Proxies funciona bien, incluso entre diferentes JVM, por ejemplo. como se usa para la Sesión-Replicación.

@Configuration public class SpringConfig { 
@Bean 
@Scope(proxyMode = ScopedProxyMode.INTERFACES) 
MyService myService() { 
    return new MyService(); 
} 
..... 

Sólo hay que ajustar el ID de la ApplicationContext antes se actualiza el contexto (véase: org.springframework.beans.factory.support.DefaultListableBeanFactory.setSerializationId (String))

AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); 
// all other initialisation part ... 
// before! refresh 
ctx.setId("portal-lasg-appCtx-id"); 
// now refresh .. 
ctx.refresh(); 
ctx.start(); 

Funciona bien en Spring-Version: 4.1.2.RELEASE

Cuestiones relacionadas