Spring会话范围的bean(控制器)和对服务的引用,就序列化而言
- 一个标准的案例 – 你有一个控制器(
@Controller
)和@Scope("session")
。 - 例如,放在会话中的类通常需要实现
Serializable
以便在服务器重新启动的情况下可以进行物理存储 - 如果控制器实现
Serializable
,这意味着它所指的所有服务(其他spring bean)也将被序列化。 他们通常是代理人,提及交易pipe理者,实体经理工厂等。 - 某些服务甚至控制器通过实现
ApplicationContextAware
来持有对ApplicationContext
的引用不是不太可能,所以这可以有效地表示整个上下文被序列化。 而且,由于它具有许多联系 – 即不能被想法序列化的东西,它将会在腐败状态下被恢复。
到目前为止,我一直忽略这些问题。 最近我想到了声明所有的spring依赖关系是transient
并通过静态工具类WebApplicationContextUtils
readResolve()
它们返回到readResolve()
,并将请求/ ServletContext保存在ThreadLocal
。 这很乏味,但它保证,当对象被反序列化时,其依赖关系将与当前应用程序上下文“最新”。
有没有任何公认的做法,或任何序列化的spring上下文的指导方针。
请注意,在JSF中,托pipe的bean(〜控制器)是有状态的(与基于动作的Web框架不同)。 所以也许我的问题比JSF更适合spring-mvc。
在这个演示文稿中 (约1:14),演讲者说,这个问题在Spring 3.0中通过提供一个不可序列化bean的代理来解决,它从当前的应用上下文(反序列化)
我希望将控制器的范围定义为“单例”,即每个应用程序一次,而不是会话。
会话范围通常用于存储每个用户的信息或每个用户的function。
通常,我只是在会话中存储“用户”对象,也许有些bean用于身份validation等。 而已。
看一下spring文档,在会话范围中使用aop代理configuration一些用户数据:
希望有所帮助
看来,赏金没有吸引到一个单一的答案,所以我会logging我有限的理解:
@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!"); } }
Spring将不会将裸体MyService注入到IndexBean中,而是一个可序列化的代理。 (我testing过了,它工作)。
但是,春季文档写道 :
您不需要将
<aop:scoped-proxy/>
与限定为singletons
或prototypes
bean结合使用。 如果您尝试为单例bean创build一个范围代理,则引发BeanCreationException
。
至less在使用基于java的configuration时,bean和它的代理可以被实例化,也就是说不引发exception。 但是,看起来像使用作用域代理来实现可序列化不是这种代理的预期用途。 因此,我担心Spring可能会修复这个“bug”,并阻止通过基于Java的configuration创build范围代理。
此外,还有一个限制:重新启动Web应用程序后,代理的类名是不同的(因为代理的类名是基于用来构造它的通知的哈希码,而这又取决于哈希码的哈希码一个拦截器的类对象,Class.hashCode不会覆盖Object.hashCode,这在重启时是不稳定的)。 因此,序列化会话不能被其他VM使用或重新启动。
我最近把JSF和Spring结合起来了。 我使用RichFaces和@KeepAlivefunction,该function序列化支持页面的JSF bean。 有两种方法我已经得到这个工作。
1)在JSF支持bean上使用@Component(“session”)
2)在需要的时候从ELContext获取bean,如下所示:
@SuppressWarnings("unchecked") public static <T> T getBean(String beanName) { return (T) FacesContext.getCurrentInstance().getApplication().getELResolver().getValue(FacesContext.getCurrentInstance().getELContext(), null, beanName); }
尝试了所有不同的selectbuild议后,我所要做的就是添加aop:scoped-proxy到我的bean定义,并开始工作。
<bean id="securityService" class="xxx.customer.engagement.service.impl.SecurityContextServiceImpl"> <aop:scoped-proxy/> <property name="identityService" ref="identityService" /> </bean>
securityService被注入到我的托pipebean,这是视图作用域。 这似乎工作正常。 根据春季文档,这应该抛出一个BeanCreationException,因为securityService是一个单身人士。 但是,这似乎并没有发生,它工作正常。 不知道这是一个错误还是副作用。
Dynamic-Proxies的序列化运行良好,即使在不同的JVM之间也是如此。 用于会话复制。
@Configuration public class SpringConfig { @Bean @Scope(proxyMode = ScopedProxyMode.INTERFACES) MyService myService() { return new MyService(); } .....
您只需在刷新上下文之前设置ApplicationContext的id(请参阅: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();
在Spring-Version:4.1.2.RELEASE上正常工作