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

如何在反序列化时重新附加单例springbean

  •  8
  • Ladlestein  · 技术社区  · 14 年前

    假设我有一个进程bean,它依赖于存储库bean。存储库bean的作用域是单例的,但流程bean的作用域是原型的。我定期序列化进程,然后稍后反序列化它。

    class Process {
       private Repository repository;
       // getters, setters, etc.
    }
    

    我不想序列化和反序列化存储库。我也不想将“transient”放在成员变量上,该变量在进程中包含对它的引用,也不想引用某种代理,或者除了声明为存储库的普通旧成员变量之外的任何东西。

    我想我想要的是让流程用一个可序列化的代理来填充它的依赖关系,该代理指向存储库(带有一个临时引用),并且在反序列化之后,可以再次找到存储库。我怎样才能定制Spring来做到这一点呢?

    我想我可以使用代理来保存依赖引用,就像。我真希望我能用那种技术。但是我看到的Spring生成的代理是不可序列化的,文档中说如果我将它与单例bean一起使用,我会得到一个异常。

    我可以在单例bean上使用一个定制范围,当请求定制范围的bean时,它总是提供一个代理。这是个好主意吗?其他想法?

    6 回复  |  直到 14 年前
        1
  •  1
  •   Pablojim    14 年前

    在反序列化对象时,如何使用方面添加注入步骤?

    为此,您需要AspectJ或类似的工具。它的工作原理与Spring中的@Configurable函数非常相似。

    本文也可能有助于: http://java.sun.com/developer/technicalArticles/Programming/serialization/

        2
  •  3
  •   nlebas    13 年前

    public class Process implements HttpSessionActivationListener {
        ...
        @Override
        public void sessionDidActivate(HttpSessionEvent e) {
            ServletContext sc = e.getSession().getServletContext();
            WebApplicationContext newContext = WebApplicationContextUtils
                .getRequiredWebApplicationContext(sc);
            newContext.getAutowireCapableBeanFactory().configureBean(this, beanName);
        }
    }
    

    该示例适用于应用程序服务器序列化会话的web环境,但它应该适用于任何ApplicationContext。

        3
  •  3
  •   Community Romance    4 年前

    看一下spring文档 http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/aop.html#aop-atconfigurable .

    7.8.1使用AspectJ向Spring注入依赖域对象

    支持用于在外部创建的对象 这是因为它们通常是以编程方式创建的

    诀窍是使用加载时编织。只需启动jvm-javaagent:path/to/org.springframework.instrument-{version}.jar。此代理将识别实例化的每个对象,如果它用@Configurable注释,它将配置(注入@Autowired或@Resource dependencies)该对象。

    只需将Process类更改为

    @Configurable
    class Process {
    
       @Autowired
       private transient Repository repository;
       // getters, setters, etc.
    }
    

    创建新实例时

    Process process = new Process();
    

    如果进程对象被反序列化,这也可以工作。

        4
  •  1
  •   Gray droiddeveloper    14 年前

    不如用某种ProcessWrapper bean来代替它,它可以是单例的。它将被注入到存储库中,或者管理进程的反序列化,或者为其设置一个setter。在包装器中设置新进程时,它将调用 setRepository() 在这个过程中。使用流程的bean可以由包装器设置为新的bean,也可以调用将委托给流程的ProcessWrapper。

    class ProcessWrapper {
       private Repository repository;
       private Process process;
       // getters, setters, etc.
    
       public void do() {
          process.do();
       }
    
       public void setProcess(Process process) {
          this.process = process;
          this.process.setRepository(repository);
       }
    }
    
        5
  •  1
  •   Ladlestein    14 年前

    回答我自己的问题:到目前为止,我是如何解决这个问题的,就是创建一个基类,使用一个便宜的小代理来序列化和反序列化。代理只包含bean的名称。

    public abstract class CheaplySerializableBase 
       implements Serializable, BeanNameAware {
    
        private String name;
    
        private static class SerializationProxy implements Serializable {
    
            private final String name;
    
            public SerializationProxy(CheaplySerializableBase target) {
                this.name = target.name;
            }
    
            Object readResolve() throws ObjectStreamException {
                return ContextLoader.globalEvilSpringContext.getBean(name);
            }
    
        }
    
        @Override
        public void setBeanName(String name) {
            this.name = name;
        }
    
        protected Object writeReplace() throws ObjectStreamException {
            if (name != null) {
                return new SerializationProxy(this);
            }
            return this;
        }
    }
    

    得到的序列化对象大约是150字节(如果我没记错的话)。

        6
  •  0
  •   izilotti    6 年前

    applicationContext.getAutowireCapableBeanFactory().autowireBean(detachedBean); 可用于重新配置序列化然后反序列化的Spring托管bean(其 @Autowired 田地变成 null ). 参见下面的示例。为了简单起见,省略了序列化细节。

    public class DefaultFooService implements FooService {
    
        @Autowired
        private ApplicationContext ctx;
    
        @Override
        public SerializableBean bar() {
            SerializableBean detachedBean = performAction();
            ctx.getAutowireCapableBeanFactory().autowireBean(detachedBean);
            return detachedBean;
        }
    
        private SerializableBean performAction() {
            SerializableBean outcome = ... // Obtains a deserialized instance, whose @Autowired fields are detached.
            return outcome;
        }
    
    }
    
    
    public class SerializableBean {
    
        @Autowired
        private transient BarService barService;
    
        private int value;
    
        public void doSomething() {
            barService.doBar(value);
        }
    
    }