Tuesday, April 23, 2013

Dependency Injection in Spring - Short Article


Any software's life depends upon it's architecture and design. Stronger is the design better would be the sustainability against the series of changes that come along with the journey. Weaker design makes the software vulnerable and thus fragile. There are certain design principles that act as the pillars of good design. You may not be knowing the design patterns but following these principles could lead you to strong design. 

The beauty of java is that it's frameworks force you to follow certain principles. One of these is Dependency Inversion in Spring.

Let us understand this principle through a hypothetical example. Suppose there is a car manufacturing unit which manufactures different models of the car. Now, initial code may look like this:

class CarManufacturingUnit
{
 public void setup(int index)
{
    if (index == 0)
    {
      return new Omni();
    }
    else if (index == 1)
    {
      return new Alto();
    }
    else ...
  }
}

CarManufacturingUnit --> Omni, Alto

Here the class CarManufacturingUnit is directly depending on the low level classes  of different car models viz. Omni, Alto, Esteem, Swift etc.. That means any modifications done to these low level classes would eventually may modify the high level class as well. We may not want to get into the situation where code suffers from the ripple effect of any small change which would then result in increasing testing effort as QA would have to test other scenarios as well.

To get out of this problem we could create an abstraction layer between these two levels. The high level class would depend only on the abstraction of these low level classes. Some what like this:

class CarManufacturingUnit
{
  private CarFactory carFactory;
  public void setup(int index)
  {
    CarModel carModel = carFactory.getCar(index);
  }
  
}

class CarFactory
{
  CarModel getCar(int index)
  {
    if (index == 0)
    {
      return new Omni();
    }
    else if (index ==1)
    {
      return new Alto();
    }
    else ...
  }
}

Here, CarManufacturingUnit doesn't depend directly upon the low level classes, rather an abstraction layer CarModel has been created.

CarManufacturingUnit --> CarModel <-- Omni, Alto

Thus by having the abstraction we have inverted the dependency. Now car manufacturing unit doesn't depends directly on models of the car. Changing any of these models wouldn't effect the high level class. 

The principle is also called as Inversion of Control(IoC). This dependency Inversion can very easily achieved using factory class or factory methods which segregate the object creation logic from the main business method.

Now when we study spring in Java we would found that this is the core principle of spring technology. Spring achieves this principle and forces in developers to use this by Dependency Injection technique.

class CarManufacturingUnit
{
  private CarFactory carFactory;
  
  public void setCarFactory(CarFactory carFactory)
  {
    this.carFactory = carFactory;
  }
  public void setup(int index)
  {
    CarModel carModel = carFactory.getCar(index);
  }
  
}

The low level object creation role has been taken care by spring container's initialization logic itself. Whenever the object is instantiated it's dependencies are also get initiated automatically. 

In the above example, we have provided setter method for carFactory member variable. The entry in bean registry XML creates the bean of CarFactory and injects it's object in dependent class, CarManufacturingUnit via setter method. We can have constructor as well in place of setter.

Entry in spring bean:

<bean id="CarManufacturingUnit" class="CarManufacturingUnit">
     <property name="carFactory" ref="carFactory"/>
</bean>


<bean id="carFactory" class="CarFactory">
</bean>


Thus spring has completely segregated the business logic and object creation logic. Developer needs not to take care of objects life cycle as well. Spring controls the their life cycle pretty well.

I tried to cover Dependency Inversion / IoC principle implemented inside Spring container.

1 comment: