Spring

Spring : Injecting Prototype Beans Into Singleton Instance

Introduction:

In the Spring framework when we inject a prototype bean into a singleton bean, it still behaves as a singleton. It’s known as prototype-bean injection problem.

In this tutorial, we’ll learn ways in which we can inject a prototype instance into a singleton bean in Spring. It’s a scenario we’re most likely to encounter in our day-to-day applications with Spring framework. Also, it’s a very popular Spring interview question.

Problem Definition:

Let’s define two beans SingletonInst and PrototypeInst:

<beans>
    ...
    <bean id = "singletonInst" class = "com.programmergirl.beans.SingletonInst">
    </bean>

    <bean id = "prototypeInst" class = "com.programmergirl.beans.PrototypeInst"
       scope="prototype">
    </bean>
</beans>

Notice that the scope of our bean with id as prototypeInst is defined to be prototype. Our singletonInst bean is singleton by default.

Let’s try to inject our bean PrototypeInst into SingletonInst:

public class SingletonInst {

    @Autowired
    private PrototypeInst prototypeInst;

    public PrototypeInst getPrototypeInst() {
        return prototypeInst;
    }
}

And now load our ApplicationContext:

ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

SingletonInst singleton1 = (SingletonInst) context.getBean("singletonInst");
SingletonInst singleton2 = (SingletonInst) context.getBean("singletonInst");

//both singleton1 and singleton2 refers to the same instance of PrototypeInst
System.out.println(singleton1.getPrototypeInst().equals(singleton2.getPrototypeInst()));

The above print() statement prints true. It confirms that both singleton1 and singleton2 refers to the same instance of PrototypeInst bean. With this, we can conclude that our PrototypeInst bean is behaving just like a singleton bean.

Solutions:

We can opt for any one of the below approaches:

1.) Injecting ApplicationContext:

We can inject the ApplicationContext into our singleton bean. To do so, we can either use @Autowired annotation or implement the ApplicationContextAware:

public class SingletonInst implements ApplicationContextAware {
 
    private ApplicationContext applicationContext;
 
    public PrototypeInst getPrototypeInst() {
        return applicationContext.getBean(PrototypeInst.class);
    }
 
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) 
      throws BeansException {
        this.applicationContext = applicationContext;
    }
}

Note that we’re using ApplicationContext to instantiate our PrototypeInst bean. The method getPrototypeInst() will each time return a new instance of our PrototypeInst bean.

Here, we are requesting the dependencies directly from the container. It is not a recommended approach as it contradicts the Principle of Dependency Inversion. 

 

2.) Method Injection:

We can also use method injection to solve this problem. It involves using @Lookup annotation:

@Component
public class SingletonInst {
 
    @Lookup
    public PrototypeInst getPrototypeInst() {
        return null;
    }
}

Note that our getPrototypeInst() has just a dummy implementation. Spring overrides the method annotated with @Lookup which then registers the bean into the ApplicationContext. Therefore each time we invoke getPrototypeInst(), we get a new instance of PrototypeInst.

Spring implements method injection by using CGLIB to generate the bytecode responsible for dynamically overriding the method marked with the @Lookup annotation.

It is recommended to mark the lookup method as abstract. The only thing to keep in mind is that the class will also have to marked as abstract for such a case.

3) ObjectFactory Interface:

ObjectFactory<T> interface in Spring helps us produce on-demand objects of any given type T.

public class SingletonInst {
 
    @Autowired
    private ObjectFactory<PrototypeInst> objectFactory;
 
    public PrototypeInst getPrototypeInst() {
        return objectFactory.getObject();
    }
}

It’s a pretty simple and intuitive approach. As usual, a new instance of PrototypeInst is created for each request.

Conclusion:

In this article, we have looked at some of the solutions to the prototype-bean injection problem in Spring.

 

One comment
Pingback: Spring Core Annotations | Hiya Android - Android World

Leave a Comment

Your email address will not be published. Required fields are marked *