Tuesday, March 5, 2013

Dependency Injection and Spring

When it comes to Spring, it always said that Dependency Injection is the major feature of Spring. In the last post i gave an example on how to use spring with a very basic example.

Let's see what's dependency injection is?

In Object oriented world, each and every application is collection of objects working together. In order to work together, there might me some relation (dependency in general sense) between the objects.

For example, i take an application of polymorphism in Java.

package com.test.appl;
public interface Shape 
{ 
     public abstract void draw();
}
package com.test.appl;
public class Rectangle implements Shape 
{
   @Override
   public void draw() 
   {
       System.out.println("Drawing Rectangle");
   }
}
package com.test.appl;

public class Triangle implements Shape 
{
   @Override
   public void draw() 
   {
       System.out.println("Drawing Triangle");
   }
}
It's a very old story. Let me repeat it again. Triangle and Rectangle are types of Shape. The methods of types will be called based on the object assigned to reference of Shape Class.

package com.test.appl;

public class Main 
{ 
   public static void main(String...strings)
   {
       Shape traingle = new Triangle();
       traingle.draw();
  
       Shape rectangle = new Rectangle();
       rectangle.draw();
   }
}

But there is dependency between the objects creation and assigning it to Shape references, and we do call at the same time when it was created. In short, they are tightly coupled.

We can slightly remove the dependency between Parent and its types, by creating an helper class, say ShapeHelper as defined below.

package com.test.appl;

public class ShapeHelper 
{ 
    private Shape shape;
 
    public ShapeHelper(Shape shape)
    {
        this.shape = shape;
    }
 
    public void doDraw()
    {
        shape.draw();
    }
}

ShapeHelper is the class which accepts an object of type Shape (can be Triangle or Rectangle in the current scenario . A method doDraw() is added which internally calls the draw method of Shape type. So, if we assign shape to an object of Rectangle , it calls the draw method of Rectangle(basic of runtime polymorphism). 

package com.test.appl;

public class MainWithHelper {
 
    public static void main(String...strings)
    {
        ShapeHelper sHelper = new ShapeHelper(new Triangle());
        sHelper.doDraw();
        Triangle t = new Triangle();
        sHelper = new ShapeHelper(t);
        sHelper.doDraw();
        sHelper = new ShapeHelper(new Rectangle());
        sHelper.doDraw();
    }
}

From the above example, the dependency in assigning of the objects to Shape has been removed with the help of an Helper Class. The shape is said to be injected into the ShapeHelper class.

This way of removing the dependency between the objects by injecting is called Dependency Injection (in other words. but not exactly)

Spring does this for us, with a simple xml configuration. Instantiation of objects and injecting the dependencies will be done by Spring configuration xml file(In short spring context file).

Let's write the same example in Spring with spring-context file as spring context file
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans" xsi:schemalocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
 
    <bean class="com.test.appl.Triangle" id="triangle" ></bean>
    <bean class="com.test.appl.Rectangle" id="rectangle"></bean>
  
    <bean class="com.test.appl.ShapeHelper" id="helper1">
        <property name="shape" ref="triangle">
    </property></bean>
  
</beans>
I have created two different beans (one for triangle and one for rectangle). and one bean for Helper class. I injected the triangle bean into ShapeHelper. In the same way, we can inject rectangle bean.

Now, the question is how do we access them. See the below code on how to access. We need to create the ApplicationContext and then get the bean to call it's methods

package com.test.spring.appl;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.test.appl.ShapeHelper;

public class DIApplication 
{
    public static void main(String...strings)
    {
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-context.xml");
        ShapeHelper helper = (ShapeHelper)context.getBean("helper1");
        helper.doDraw();
    }
}

The the helper will call the draw() of triangle as the injected object is triangle  To call the draw method to Rectangle, we can change the xml file rather than the actual code. That is another advantage of Spring.