代码之家  ›  专栏  ›  技术社区  ›  Bozho

Spring会话范围的bean(控制器)和对服务的引用,在序列化方面

  •  43
  • Bozho  · 技术社区  · 14 年前
    • 一个标准案例-你有一个控制器( @Controller @Scope("session") .
    • Serializable 以便在服务器重新启动时可以物理地存储它们
    • 如果控制器执行 可序列化 ,这意味着它引用的所有服务(其他springbean)也将被序列化。它们通常是代理,引用事务管理器、实体管理器工厂等。
    • ApplicationContext ,通过实施 ApplicationContextAware ,因此这实际上意味着整个上下文是序列化的。并且考虑到它有很多连接——也就是说,不能通过idea序列化的东西,它将在损坏的状态下恢复。

    transient 把他们弄回来 readResolve() 通过静态实用程序类 WebApplicationContextUtils ThreadLocal . 这是乏味的,但它保证,当对象被反序列化时,它的依赖项将与

    对于这一点,是否有任何公认的实践,或者对spring上下文的某些部分进行序列化的指导方针。

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

    6 回复  |  直到 11 年前
        1
  •  19
  •   Hans Westerbeek    12 年前

    this presentation (大约1:14)演讲者说这个问题在Spring3.0中通过提供一个不可序列化bean的代理来解决,该代理从 现在的 应用程序上下文(反序列化时)

        2
  •  8
  •   meriton    13 年前

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

    @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文档 writes :

    你知道吗 需要使用 <aop:scoped-proxy/> 与范围为 singletons prototypes . 如果尝试为单例bean创建作用域代理,则 BeanCreationException 升起。

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

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

        3
  •  7
  •   laher    14 年前

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

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

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

    希望有帮助

        4
  •  2
  •   Thomas Kessler    13 年前

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

    2) 在需要的时候从ELContext获取bean,比如:

    @SuppressWarnings("unchecked")
    public static <T> T  getBean(String beanName) {
        return (T) FacesContext.getCurrentInstance().getApplication().getELResolver().getValue(FacesContext.getCurrentInstance().getELContext(), null, beanName);
    }
    
        5
  •  2
  •   user1159790    13 年前

    在尝试了所有不同的选择之后,我所要做的就是添加 aop:scoped-proxy

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

    securityService被注入到视图范围内的managedbean中。这似乎很管用。根据spring文档,这应该抛出BeanCreationException,因为securityService是单例的。然而,这似乎没有发生,它的工作很好。不确定这是一个错误还是会有什么副作用。

        6
  •  1
  •   Martin Harm    10 年前

    的序列化 即使在不同的jvm之间也能很好地工作,例如用于会话复制。

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

    刷新上下文(请参见: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版本4.1.2.RELEASE上运行良好