Singleton beans with prototype-bean dependencies

Note: This is an excerpt from the Spring documentation.

In most application scenarios, most beans in the container are singletons. When a singleton bean needs to collaborate with another singleton bean, or a non-singleton bean needs to collaborate with another non-singleton bean, you typically handle the dependency by defining one bean as a property of the other.

When you use singleton-scoped beans with dependencies on prototype beans, be aware that dependencies are resolved at instantiation time. Thus if you dependency-inject a prototype-scoped bean into a
singleton-scoped bean, a new prototype bean is instantiated and then dependency-injected into the singleton bean. The prototype instance is the sole instance that is ever supplied to the singleton-scoped bean.

So problem arises when the bean lifecycles are different. Suppose singleton bean A needs to use non-singleton (prototype) bean B, perhaps on each method invocation on A. The container only creates
the singleton bean A once, and thus only gets one opportunity to set the properties. The container cannot provide bean A with a new instance of bean B every time one is needed.

Solution 1>Application Context Aware
Make bean A aware of the container by implementing the ApplicationContextAware interface, and by making a getBean(“B”) call to the container ask for (a typically new) bean B instance every time bean A needs it.
The following is an example of this approach


// Spring-API imports
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

public class CommandManager implements ApplicationContextAware {
   private ApplicationContext applicationContext;
   public Object process(Map commandState) {
      // grab a new instance of the appropriate Command
      Command command = createCommand();
      // set the state on the (hopefully brand new) Command instance
      command.setState(commandState);
      return command.execute();
   }

   protected Command createCommand() {
      // notice the Spring API dependency!
      return this.applicationContext.getBean("command", Command.class);
   }

   public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
      this.applicationContext = applicationContext;
   }
}

Note: The preceding is not desirable, because the business code is aware of and coupled to the Spring Framework

Solution 2> Lookup method injection
Lookup method injection is the ability of the container to override methods on container managed beans, to return the lookup result for another named bean in the container. The lookup typically involves a prototype bean as in the scenario described in the preceding section. The Spring Framework implements this method injection by using bytecode generation from the CGLIB library to generate dynamically a subclass that overrides the method.
Note:
For this dynamic subclassing to work, you must have the CGLIB jar(s) in your classpath. The class that the Spring container will subclass cannot be final, and the method to be overridden cannot be final either. Also, testing a class that has an abstract method requires you to subclass the class yourself and to supply a stub implementation of the abstract method. Finally, objects that have been the target of method injection cannot be serialized.

Looking at the CommandManager class in the previous code snippet, you see that the Spring container will dynamically override the implementation of the createCommand() method. Your CommandManager class will not have any Spring dependencies, as can be seen in the reworked example:


// no more Spring imports!
public abstract class CommandManager {
   public Object process(Object commandState) {
      // grab a new instance of the appropriate Command interface
      Command command = createCommand();
      // set the state on the (hopefully brand new) Command instance
      command.setState(commandState);
      return command.execute();
   }

   // okay... but where is the implementation of this method?
   protected abstract Command createCommand();
}

In the client class containing the method to be injected (the CommandManager in this case), the method to be injected requires a signature of the following form:


<public|protected> [abstract] <return-type> theMethodName(no-arguments);

If the method is abstract, the dynamically-generated subclass implements the method. Otherwise, the dynamically-generated subclass overrides the concrete method defined in the original class.
For example:


<!-- a stateful bean deployed as a prototype (non-singleton) -->
<bean id="command" class="fiona.apple.AsyncCommand" scope="prototype">
   <!-- inject dependencies here as required -->
</bean>

<!-- commandProcessor uses statefulCommandHelper -->
<bean id="commandManager" class="fiona.apple.CommandManager">
   <lookup-method name="createCommand" bean="command"/>
</bean>

The bean identified as commandManager calls its own method createCommand() whenever it needs a new instance of the command bean. You must be careful to deploy the command bean as a prototype, if
that is actually what is needed. If it is deployed as a singleton, the same instance of the command bean is returned each time.

There is also a Solution 3> Arbitrary method replacement, but its less elegant and more complicated than Lookup method injection. So we wont go over there.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s