Injecting Prototype bean into a Singleton bean in Spring

In this post, we will see how to inject prototype bean scope into Singleton Instance in Spring. This is one of the most asked Spring interview questions.
[toc]

Problem

When you inject prototype bean to singleton bean, prototype bean still behave like a singleton bean.

Let’s understand this with the help of example.
1. Create a simple java maven project.
2. Maven dependency
put spring and cglib maven dependency in pom.xml.

  
   <dependencies>
  <dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-core</artifactId>
   <version>${spring.version}</version>
  </dependency>
  <dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-webmvc</artifactId>
   <version>${spring.version}</version>
  </dependency>
<!-- cglib required for @configuration annotation -->
   <dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib</artifactId>
            <version>3.0</version>
        </dependency>
 </dependencies>
 <properties>
  <spring.version>4.2.1.RELEASE</spring.version>
 </properties>

So your pom.xml will look like:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"<
  <modelVersion<4.0.0</modelVersion>
  <groupId>org.arpit.java2blog</groupId>
  <artifactId>SpringHelloWorldJavaBasedConfiguration</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <name>SpringHelloWorldJavaBasedConfiguration</name>
  <description>It provides hello world program for java based config
</description>

 <dependencies>
  <dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-core</artifactId>
   <version>${spring.version}</version>
  </dependency>
  <dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-webmvc</artifactId>
   <version>${spring.version}</version>
  </dependency>
<!-- cglib required for @configuration annotation -->
   <dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib</artifactId>
            <version>3.0</version>
    </dependency>
 </dependencies>
 <properties>
  <spring.version>4.2.1.RELEASE</spring.version>
 </properties>
</project>

3. Create Bean class

Create a bean class called X.java in package org.arpit.java2blog .
package org.arpit.java2blog;

import org.springframework.beans.factory.annotation.Autowired;

public class X {

    @Autowired
    Y y;

    public Y getY() {
        return y;
    }

    public void setY(Y y) {
        this.y = y;
    }
}
Create another bean class called Y.java in package org.arpit.java2blog.
package org.arpit.java2blog;

public class Y {

    public void methodY()
    {
        System.out.println("In method Y");
    }

}

4. ApplicationContext.xml
Create ApplicationContext.xml in src/main/resources as below.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-3.0.xsd">

    <bean id="x" class="org.arpit.java2blog.X">
    </bean>
    <bean id="y" class="org.arpit.java2blog.Y" scope="prototype">
    </bean>
    <context:annotation-config/>
</beans>

We have just declared two bean x and y here.
5. Create InjectPrototypeToSingletonMain.java

package org.arpit.java2blog;

import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * Injecting prototype dependencies into singleton
 *
 */
public class InjectPrototypeToSingletonMain 
{
    public static void main( String[] args )
    {
        ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("ApplicationContext.xml");
        X firstX = (X) ac.getBean("x");
        Y firstY = firstX.getY();

        X secondX = (X) ac.getBean("x");
        Y secondY = secondX.getY();
        System.out.println("do two prototype beans of type Y point to same object: "+firstY.equals(secondY));
        ac.close(); 
    }
}

6. Run it
When you run above program, you will get below output.

Jun 15, 2018 1:32:58 PM org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh
INFO: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@31cefde0: startup date [Fri Jun 15 13:32:58 IST 2018]; root of context hierarchy
Jun 15, 2018 1:32:58 PM org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
INFO: Loading XML bean definitions from class path resource [ApplicationContext.xml]
do two prototype bean point to same object: true
Jun 15, 2018 1:32:59 PM org.springframework.context.support.ClassPathXmlApplicationContext doClose
INFO: Closing org.springframework.context.support.ClassPathXmlApplicationContext@31cefde0: startup date [Fri Jun 15 13:32:58 IST 2018]; root of context hierarchy

As you can note here, even though we have declared bean Y as prototype, still it is behaving like a singleton bean only.

Solution

There are many ways to solve this problem.

Using Method injection

Update X.java as below.

package org.arpit.java2blog;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Lookup;

public class X {

    @Autowired
    Y y;

    @Lookup
    public Y getY() {
        return y;
    }

    public void setY(Y y) {
        this.y = y;
    }
}

You can use method injection to solve this problem.Simply use @Lookup with getY() method, it will return new instance each time.
Spring will use CGLIB to generate dynamically a subclass that overrides the method getY(). It then registers the bean into the application context. Whenever we request for getY() method, it will return new instance of Class Y.

There are two options here, either create dummy method or mark method as abstract. When you mark method as abstract, then you will have to declare class abstract as well, hence we have used dummy method in this scenario.

Run InjectPrototypeToSingletonMain again
You will get below output:

Jun 15, 2018 1:51:38 PM org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh
INFO: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@31cefde0: startup date [Fri Jun 15 13:51:38 IST 2018]; root of context hierarchy
Jun 15, 2018 1:51:38 PM org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
INFO: Loading XML bean definitions from class path resource [ApplicationContext.xml]
do two prototype beans of type Y point to same object: false
Jun 15, 2018 1:51:38 PM org.springframework.context.support.ClassPathXmlApplicationContext doClose
INFO: Closing org.springframework.context.support.ClassPathXmlApplicationContext@31cefde0: startup date [Fri Jun 15 13:51:38 IST 2018]; root of context hierarchy

As you can note now, we are getting two different instance of Y now.

Using ObjectFactory

You can use ObjectFactory to get new object each time getY() method is called.
Update class A.java as below

package org.arpit.java2blog;

import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.annotation.Autowired;

public class X {

    @Autowired
    private ObjectFactory<Y> prototypeBeanObjectFactory;

    Y y;

    public Y getY() {
        return prototypeBeanObjectFactory.getObject();
    }

    public void setY(Y y) {
        this.y = y;
    }
}

Run InjectPrototypeToSingletonMain again
You will get below output:

Jun 15, 2018 2:55:56 PM org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh
INFO: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@31cefde0: startup date [Fri Jun 15 14:55:56 IST 2018]; root of context hierarchy
Jun 15, 2018 2:55:57 PM org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
INFO: Loading XML bean definitions from class path resource [ApplicationContext.xml]
do two prototype beans of type Y point to same object: false
Jun 15, 2018 2:55:58 PM org.springframework.context.support.ClassPathXmlApplicationContext doClose
INFO: Closing org.springframework.context.support.ClassPathXmlApplicationContext@31cefde0: startup date [Fri Jun 15 14:55:56 IST 2018]; root of context hierarchy

Using ApplicationContextAware

You can return new bean using application context wheneven getY() method is getting called.
Update class A.java as below

package org.arpit.java2blog;

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

public class X implements ApplicationContextAware{

    private ApplicationContext applicationContext;

    Y y;

    public Y getY() {
        return applicationContext.getBean(Y.class);
    }

    public void setY(Y y) {
        this.y = y;
    }

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

Run InjectPrototypeToSingletonMain again
You will get below output:

Jun 15, 2018 2:58:59 PM org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh
INFO: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@31cefde0: startup date [Fri Jun 15 14:58:59 IST 2018]; root of context hierarchy
Jun 15, 2018 2:58:59 PM org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
INFO: Loading XML bean definitions from class path resource [ApplicationContext.xml]
do two prototype beans of type Y point to same object: false
Jun 15, 2018 2:59:00 PM org.springframework.context.support.ClassPathXmlApplicationContext doClose
INFO: Closing org.springframework.context.support.ClassPathXmlApplicationContext@31cefde0: startup date [Fri Jun 15 14:58:59 IST 2018]; root of context hierarchy

That’s all about Injecting Prototype bean into a Singleton bean in Spring.

For more questions, refer Spring interview questions.

[social_share share_on="facebook,twitter,linkedin,whatsapp"][post_navigator in_same_term="true"]

Leave a Reply

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

Subscribe to our newletter

Get quality tutorials to your inbox. Subscribe now.