Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to reattach singleton Spring beans upon deserialization

I want to reinject singleton-scoped dependencies into prototype Spring beans, after they have been deserialized.

Say I've got a Process bean, which depends on a Repository bean. The Repository bean is a scoped as a singleton, but the Process bean is prototype-scoped. Periodically I serialize the Process, and then later deserialize it.

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

I don't want to serialize and deserialize the Repository. Nor do I want to put "transient" on the member variable that holds a reference to it in Process, nor a reference to some kind of proxy, or anything other than a plain old member variable declared as a Repository.

What I think I want is for the Process to have its dependency filled with a serializable proxy that points (with a transient reference) to the Repository, and, upon deserialization, can find the Repository again. How could I customize Spring to do that?

I figure I could use a proxy to hold the dependency references, much like . I wish I could use that exact technique. But the proxy I've seen Spring generate isn't serializable, and the docs say that if I use it with a singleton bean, I'll get an exception.

I could use a custom scope, perhaps, on the singleton beans, that would always supply a proxy when asked for a custom-scoped bean. Is that a good idea? Other ideas?

like image 399
Ladlestein Avatar asked Aug 12 '10 20:08

Ladlestein


2 Answers

I used this instead, without any proxy:

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);
    }
}

The example is for a web environment when the application server serializes the session, but it should work for any ApplicationContext.

like image 104
nlebas Avatar answered Sep 24 '22 03:09

nlebas


Spring provides a solution for this problem.

Take a look at the spring documentation http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/aop.html#aop-atconfigurable.

7.8.1 Using AspectJ to dependency inject domain objects with Spring

...

The support is intended to be used for objects created outside of the control of any container. Domain objects often fall into this category because they are often created programmatically using the new operator, or by an ORM tool as a result of a database query.

The trick is to use load time weaving. Just start the jvm with -javaagent:path/to/org.springframework.instrument-{version}.jar. This agent will recognize every object that is instantiated and if it is annotated with @Configurable it will configure (inject @Autowired or @Resource dependencies) that object.

Just change the Process class to

@Configurable
class Process {

   @Autowired
   private transient Repository repository;
   // getters, setters, etc.
}

Whenever you create a new instance

Process process = new Process();

spring will automatically inject the dependencies. This also works if the Process object is deserialized.

like image 29
René Link Avatar answered Sep 25 '22 03:09

René Link