Skip to main content

Spring: Method Injection

This is useful when a Singleton bean need to use a non-singleton bean. Sometime your application may need to collaborate a prototype bean with a singleton bean to satisfy your business logic. That is your singleton bean is dependent on a prototype bean. Let’s consider three beans
  1. Customer
  2. Sales Person
  3. Product

A customer may ask a sales Person to show different type of products from the repository. Let’s assume you have gone to a garment shop to buy a new shirt for the lucky date with your new girlfriend. So, it’s a tough choice and you may like to try different colors and styles and finally you will choose one.

So, if we describe the above situation in the form of business logic inside one of your module, it will look like this,

The sales Person should show a new product every time he requests. Let’s assume Customer and Sales Person to be singleton bean in your Spring container and Product as prototype. But based on bean life-cycle a prototype bean can not be injected to a singleton bean. In this case Customer and Sales Person is singleton, hence Sales Person cannot request a new Product, it's being a prototype. But Spring has a solution and that is Method Injection.

The Customer Class:

public class Customer {
      @Autowired
      private SalesPerson salesPerson;
     
      public Customer() {
            System.out.println("Customer arrived");
      }
     
      public void askProduct() {
            System.out.println("Ask for product");
            salesPerson.bringProduct();
      }
}

The Product Class:

public class Product {
      private int i = 0;
      public Product() {
            System.out.println("product loaded");
      }
     
      public void showProduct() {
            System.out.println("Get product ID " + i++);
      }
}


The SalesPerson Class:

public abstract class SalesPerson {
      protected abstract Product getFromRepository();
     
      public SalesPerson() {
            System.out.println("Sales person called");
      }
     
      public void bringProduct() {
            getFromRepository().showProduct();
      }
}


The Main Class:

public class BuyShirtForMyDate {
      public static void main(String[] args) {
            ApplicationContext context = new ClassPathXmlApplicationContext("META-INF/spring-context.xml");
            Customer customer = (Customer) context.getBean("customer");
            customer.askProduct();
            customer.askProduct();
           
           
      }
}

The Spring context:

<bean id="customer" class="Customer" />
<bean id="product" class="Product" scope="prototype"/>
     
<bean id="salesPerson" class="SalesPerson">
        <lookup-method bean="product" name="getFromRepository"/>
</bean>

Output

Customer arrived
Sales person called
Ask for product
New product loaded
Get product ID 0
Ask for product
New product loaded
Get product ID 0

From the above example you can see that, SalesPerson is an abstract class, generally spring can not create a bean of the abstract class, in this case spring will subclass your SalesPerson class dynamically and override the lookup-method, that is getFromRepository.

The method that is to be 'injected' must have a signature of the following form:
<public|protected> [abstract] <return-type> theMethodName(no-arguments);

Also you can see that product is a prototype bean. Whenever a bean request comes Spring will execute getFromRepository method in SalesPerson class and will return a new Product bean. Hope this discussion makes some sense.

Comments

Popular posts from this blog

Copying objects – Java Clonable interface

We can assign reference of an object to another, provided each of them satisfies an “ is-a” relationship or of same type. For example, a Dog object can hold the reference of another Dog object regardless both have different states. Similarly an Animal object can hold the reference of a Dog or Cat object, if they satisfies an “is-a” relationship. But hold on, these assignments do not help you to create a duplicate copy of the object. It’s nothing but different pointers pointing to the same memory location. Java provides API to clone an object. Using this API one can get a copy of an object to another. To achieve this, proposed class should implement Clonable interface (else JVM will throw CloneNotSupportedException during runtime). The rationale behind cloning is to get an independent copy of an object. The Object class has a clone() method which takes care of this operation. This method is protected by nature and returns an Object , when called.   You can call this ...

JUnit Rule : Creating Temporary Folder

I was surprised to see this beautiful feature in JUnit and it helped to ease to lots of constrains I face while writing JUnit tests. I basically follow TDD and as you guys know we focus more on writing tests, hence it is necessary to use some shortcuts availed by the tools like JUnit to make the process fast. Recently I had an issue where I had to create and delete a file before and after every test executes. I did that using @Before and @After annotation of Junit and it worked, however I was looking for more of a generic way to do this at one place. As I started googling I came across this post, which is amazing,  After reading the block I know how I can generalize my creating and deleting of a temporary file or folder (I decided to go with a temporary folder and a file inside it, which looks more readable and oganized). The JUnit class: public class TemporaryFolderTestCase { @Rule public TemporaryFolder temporaryFolder = new TemporaryF...