13 - Method Injection in Spring

13.1 Overview

We discussed Constructor and Setter based dependency injection in earlier chapters and in his chapter we will discuss Method injection. In Constructor and Setter based dependency Injection, Spring creates the beans and injects them using the constructor or setter method but with Method Injection approach dependencies are resolved using method look ups in which specified method of given bean is called to get the bean instance.

13.2 Why do we need Method Injection?

Method Injection should be used is when a Singleton bean has a dependency on Prototype bean.

We know that the Spring beans can be created with singleton or prototype scope.

  • Singleton: Instantiate only one object
  • Prototype: Instantiate a new object every time.

Spring container resolves the dependencies at instantiation time which means if any singleton bean has  a dependency of any prototype bean, then a new object of prototype bean will be instantiated and injected in to singleton bean at the time of instantiation of Singleton bean.

With this, the same prototype bean will always supplied from singleton bean.

Confused? Consider a Singleton Bean “A” which has a dependency of non singleton (prototype) bean “B” .Container will create only one instance of bean “A” thus will have only one opportunity to inject the prototype bean “B” in it and every time  you makes a call to get bean B from bean A , always the same bean will be returned.

Lets write an  example to see the above concept working

Write a ProptotypeBean like below

public class PrototypeBean {
       private String message;
       public PrototypeBean()
       {
          System.out.println("Prototype Bean Instantiated !!");
       }      
       public void setMessage(String message){
          this.message  = message;
       }
       public String  getMessage(){
          return this.message;
       }
}

Write a SingletonBean which has a dependency on PrototypeBean like below

public class SingletonBean {
       private PrototypeBean prototypeBean;
       public SingletonBean()
       {
           System.out.println("Singleton Bean Instantiated !!");
       }
       public PrototypeBean getPrototypeBean() {
           return prototypeBean;
       }
       public void setPrototypeBean(PrototypeBean prototypeBean) {
           this.prototypeBean = prototypeBean;
       }
}

 Define beans.xml to configure SingletonBean and PrototypeBean

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
       <bean id="prototypeBean" class="PrototypeBean" scope="prototype">
              <property name="message" value="Test Message" />
       </bean>      
       <bean id="singletonBean" class="SingletonBean" >
              <property name="prototypeBean" ref="prototypeBean"/>                    
       </bean>      
</beans>

Create test program to test the behaviour

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestProgram {
public static void main(String[] args) {
       ApplicationContext context =
       new ClassPathXmlApplicationContext("beans.xml");
       SingletonBean singleton = (SingletonBean)context.getBean("singletonBean");             
       PrototypeBean prototypeBeanA = singleton.getPrototypeBean();
       PrototypeBean prototypeBeanB = singleton.getPrototypeBean();             
       System.out.println(prototypeBeanA);
       System.out.println(prototypeBeanB);             
       System.out.println("Is prototypeBeanA and prototypeBeanA  same ? " + (prototypeBeanA==prototypeBeanB));
       }
}

Run the program and we can see that getPrototypeBean() returned same object both time

If we need to have a different prototype bean instance every time than we have got two approaches

  1. Method Injection
  2. Use of ApplicationContextAware interface

13.3 How to use Method Injection

We need to create an abstract method in Singleton class with return type as  PrototypeBean .and Prototype bean class will declare one method which returns the current instance (this).

Spring provides below tag that can be used for method injection.

       “<lookup method name=”prototype_bean” value=”method_name”/>

 

This tag specifies that dependency will be resolved by calling method of a bean and since the bean is of type prototype, we will get new instance on every call.

SingletonBean.java
public abstract class SingletonBean {
       public SingletonBean()
       {
              System.out.println("Singleton Bean Instantiated !!");
       }
       public abstract PrototypeBean getPrototypeBean();      
}
PrototypeBean.java
public class PrototypeBean {
       private String message;
       public PrototypeBean()
       {
              System.out.println("Prototype Bean Instantiated !!");
       }      
       public void setMessage(String message){
              this.message  = message;
       }
       public String  getMessage(){
              return this.message;
       }      
       public PrototypeBean getPrototypeBean()
       {
              return this;
       }
}

Define entries of beans in beans.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
       <bean id="prototypeBean" class="PrototypeBean" scope="prototype">
              <property name="message" value="Test Message" />
       </bean>      
       <bean id="singletonBean" class="SingletonBean" >             
              <lookup-method bean="prototypeBean" name="getPrototypeBean"/>
       </bean>      
</beans>

Create test program to test the behaviour

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestProgram {
public static void main(String[] args) {
       ApplicationContext context =
       new ClassPathXmlApplicationContext("beans.xml");
       SingletonBean singleton = (SingletonBean)context.getBean("singletonBean");             
       PrototypeBean prototypeBeanA = singleton.getPrototypeBean();
       PrototypeBean prototypeBeanB = singleton.getPrototypeBean();             
       System.out.println(prototypeBeanA);
       System.out.println(prototypeBeanB);             
       System.out.println("Is prototypeBeanA and prototypeBeanA  same ? " + (prototypeBeanA==prototypeBeanB));
       }
}

Run the program and we can see that getPrototypeBean() returned different  object both time

13.4 Using Application Context Aware approach

We discussed Application Context Aware interface in earlier chapters with which we can get the instance of application context in which the bean is configured.

Every time a call getBean() for a prototype object will returns a different bean so

  1. Implements Application Context Aware interface in a singleton bean
  2. In the getter method of prototype bean, we can explicitly make a call to getBean and returns the object.
PrototypeBean.java
public class PrototypeBean {
       private String message;
       public PrototypeBean()
       {
              System.out.println("Prototype Bean Instantiated !!");
       }      
       public void setMessage(String message){
              this.message  = message;
       }
       public String  getMessage(){
              return this.message;
       }
}
SingletonBean.java
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
public  class SingletonBean implements ApplicationContextAware {
       private PrototypeBean prototypeBean;
       private ApplicationContext applicationContext;
       public SingletonBean()
       {
              System.out.println("Singleton Bean Instantiated !!");
       }
       public PrototypeBean getPrototypeBean()
{      
prototypeBean= (PrototypeBean)applicationContext.getBean("prototypeBean");
       return prototypeBean;
       }
       @Override
       public void setApplicationContext(ApplicationContext applicationContext)
                     throws BeansException {
              this.applicationContext=applicationContext;
       }
}

Define entries of beans in beans.xml – In the singleton bean , we did not add the dependency of prototype bean, instead the dependency is resolved programatically

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
       <bean id="prototypeBean" class="PrototypeBean" scope="prototype">
              <property name="message" value="Test Message" />
       </bean>      
       <bean id="singletonBean" class="SingletonBean" >
       </bean>      
</beans>

Test Program

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestProgram {
       public static void main(String[] args) {
              ApplicationContext context =
              new ClassPathXmlApplicationContext("beans.xml");
              SingletonBean singleton = (SingletonBean)context.getBean("singletonBean");             
              PrototypeBean prototypeBeanA = singleton.getPrototypeBean();             
              PrototypeBean prototypeBeanB = singleton.getPrototypeBean();             
              System.out.println(prototypeBeanA);
              System.out.println(prototypeBeanB);             
              System.out.println("Is prototypeBeanA and prototypeBeanA  same ? " + (prototypeBeanA==prototypeBeanB));
       }
}

Run the program and we can see that getPrototypeBean() returned different  object both time

13.5 Conclusion

Method Injection is the approach in which method name is configured which will be used to resolve the dependency. This approach  is primarily used when a singleton bean has a dependency on a prototype bean and a new instance of prototype bean is required from a singleton bean every time. 

Like us on Facebook