Java Spring会话范围的bean(控制器)和对服务的引用,在序列化方面 标准案例-您有一个控制器(@controller)和@Scope(“会话”) 在会话中放置的类通常需要实现Serializable,以便在服务器重新启动时物理存储它们 如果控制器实现了Serializable,这意味着它引用的所有服务(其他springbean)也将被序列化。它们通常是代理,引用事务管理器、实体管理器工厂等 通过实现ApplicationContextAware,某些服务甚至控制器不太可能持有对ApplicationContext的引用,因此这实际上意味着整个上下文被序列化。考虑到它拥有许多连接,即idea无法序列化的东西,它将在损坏状态下恢复

Java Spring会话范围的bean(控制器)和对服务的引用,在序列化方面 标准案例-您有一个控制器(@controller)和@Scope(“会话”) 在会话中放置的类通常需要实现Serializable,以便在服务器重新启动时物理存储它们 如果控制器实现了Serializable,这意味着它引用的所有服务(其他springbean)也将被序列化。它们通常是代理,引用事务管理器、实体管理器工厂等 通过实现ApplicationContextAware,某些服务甚至控制器不太可能持有对ApplicationContext的引用,因此这实际上意味着整个上下文被序列化。考虑到它拥有许多连接,即idea无法序列化的东西,它将在损坏状态下恢复,java,spring,serialization,jsf,servlets,Java,Spring,Serialization,Jsf,Servlets,到目前为止,我几乎忽略了这些问题。最近,我想声明我所有的spring依赖项transient,并通过静态实用程序类webapplicationcontextils将它们恢复到readResolve()中,并将请求/ServletContext保存在ThreadLocal中。这是乏味的,但它保证,当对象被反序列化时,其依赖项将与当前应用程序上下文“最新” 对于这一点,是否有任何公认的实践,或者是否有任何序列化spring上下文部分的指南 注意,在JSF中,托管bean(~控制器)是有状态的(与基于

到目前为止,我几乎忽略了这些问题。最近,我想声明我所有的spring依赖项
transient
,并通过静态实用程序类
webapplicationcontextils
将它们恢复到
readResolve()
中,并将请求/ServletContext保存在
ThreadLocal
中。这是乏味的,但它保证,当对象被反序列化时,其依赖项将与当前应用程序上下文“最新”

对于这一点,是否有任何公认的实践,或者是否有任何序列化spring上下文部分的指南


注意,在JSF中,托管bean(~控制器)是有状态的(与基于动作的web框架不同)。因此,也许我的问题更多地代表JSF,而不是spring mvc。

我希望将控制器范围界定为“单例”,即每个应用程序一次,而不是在会话中

会话范围通常更多地用于存储每个用户的信息或每个用户的功能

通常我只在会话中存储“user”对象,可能还有一些用于身份验证之类的bean。就这样

查看spring文档,使用aop代理在会话范围内配置一些用户数据:


希望这有助于

在(大约1:14)中,演讲者说,这个问题在spring 3.0中通过提供一个不可序列化bean的代理来解决,该代理从当前应用程序上下文(反序列化)获取一个实例

我最近将JSF与spring结合起来。我使用RichFaces和@KeepAlive特性,它序列化了支持页面的JSFbean。我有两种方法让它发挥作用

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);
}
@SuppressWarnings(“未选中”)
公共静态T getBean(字符串beanName){
返回(T)FacesContext.getCurrentInstance().getApplication().getELResolver().getValue(FacesContext.getCurrentInstance().getELContext(),null,beanName);
}

看来赏金并没有吸引到一个答案,所以我将记录我有限的理解:

@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,而是向它注入一个可序列化的代理。(我对此进行了测试,效果良好)

但是,spring文档:

您不需要将
与范围为
单例
原型
的bean结合使用。如果尝试为单例bean创建作用域代理,则会引发
BeanCreationException

至少在使用基于java的配置时,bean及其代理可以很好地实例化,即不会引发异常。但是,使用作用域代理来实现可序列化性似乎不是此类代理的预期用途。因此,我担心Spring可能会修复这个“bug”,并阻止通过基于Java的配置创建作用域代理


此外,还有一个限制:重新启动web应用程序后,代理的类名不同(因为代理的类名基于用于构造它的通知的哈希代码,而哈希代码又取决于拦截器类对象的哈希代码。class.hashcode不覆盖object.hashcode,后者在重新启动时不稳定)因此,序列化的会话不能被其他VM或跨重启使用。

在尝试了所有不同的替代方案后,我建议只需将aop:scoped proxy添加到我的bean定义中,它就开始工作了

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


securityService被注入到我的managedbean中,它是视图作用域。这似乎工作正常。根据spring文档,这应该会引发BeanCreationException,因为securityService是一个单例。但是这似乎没有发生,而且工作正常。不确定这是一个bug还是会有什么副作用。

动态代理的序列化工作良好,即使在不同JVM之间,例如用于会话复制

@Configuration public class SpringConfig {
@Bean 
@Scope(proxyMode = ScopedProxyMode.INTERFACES) 
MyService myService() {
    return new MyService();
}
.....
您只需在刷新上下文之前设置ApplicationContext的id即可(请参阅:org.springframework.beans.factory.support.DefaultListableBeanFactory.setSerializationId(字符串))


在Spring版本:4.1.2上运行良好。发布版

有时也可以使用作用域控制器。不经常,但有时。我的假设是,控制器通常属于请求作用域,因为您在其中存储了一些每个请求的信息(即非单例).只是好奇,我从来没有使用过会话范围的控制器-它在哪些情况下有用?@Bozho,传统上控制器/servlet应该没有state@mattb-在SpringMVC和传统的基于动作的框架中,是的,我同意。但在JSF中不是这样。我更新了我的问题,将JSF包括在内。找到了!滚动1小时到电影很好。它准确地解释了这个问题。它被解决了。即使没有配置。
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
// all other initialisation part ...
// before! refresh
ctx.setId("portal-lasg-appCtx-id");
// now refresh ..
ctx.refresh();
ctx.start();