Sunday, October 25, 2009

Spring DI and IoC for Beginners'

In the vocabulary of Spring, Dependency Injection (DI) is a design pattern, Inversion of Control (IoC) is a principle and IoC is implemented using DI. To understand what dependency injection means, let's consider an example.
Following is a high level class diagram for our example. The green arrows shows the generalization and the blue arrows shows the association.


Let's jump into the code for the above design. The
Repository interface exposes the displayDescription method.


The XmlRepository and DBRepository are concrete classes that implements Repository interface and they handle the persistence logic for XML and database repositories respectively. To keep things really simple, let's have the displayDescription method to return a simple string for the respective persistence logic.






The RepositoryService class acts as the service interface for the clients.



finally RespositoryServiceClient, the client program.



As you can see it is pretty simple. But, this architecture is tightly coupled. We had created an instance of the DBRepository class in the RepositoryService class in the following way.



To change our persistence logic to a Xml base repository, we need to make modifications to the RepositoryService class in the following way.



So, it is tightly coupled.

Now, let's see how we can avoid the coupling. The solution is provided by the Spring framework as it provides a container to manage components in a cohesive manner. This container adheres to the Inversion of Control (IoC) principle and Dependency Injection (DI) design pattern. With the Spring framework, the components only needs a way to accept the resources it needs and the container acts as a mediator which is responsible for delivering the resource to those components(through DI).
Let's revisit our class diagram with the presence of the Spring's IoC container that acts as a mediator.



Add the following jar files to the classpath.



Modify the RepositoryService class as follows.



Instead of having hard coded values, we will let the container to inject the required dependencies for us. The Dependency Injection (DI) can be achieved in two ways, setter injection and constructor injection. In this example we'll stick to setter injection.



The reference for a Repository class will be set using the setRepository setter method. Note that, an instance of Repository interface is never instantiated within the RepositoryService class.

Now it's time for the bean configuration. Here I am using spring-beans.xml file which is in the classpath(any name can be used).

<?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.xsd">

<!-- bean instance for xml repository -->
<bean id="xmlRepository" class="com.faz.spring.sample.XmlRepository" />

<!-- bean instance for database repository -->
<bean id="dbRepository" class="com.faz.spring.sample.DBRepository" />

<bean id="repositoryService" class="com.faz.spring.sample.RepositoryService">
<property name="repository" ref="dbRepository"/>
</bean>
</beans>

finally, the client needs to be modified as follows. The client references the beans which are managed by the Spring IoC container.



A bean is defined using the bean tag. The id attribute of the bean provides an unique reference to a bean and the class attribute represents the actual bean class. The property tag is used to refer a property of the bean. A bean can be injected to another through the ref tag. Here a bean reference of DBRepository type is injected to the bean repositoryService of type RepositoryService class. When executed, "Repository info: Display description for database repository." gets printed on the console. To make our repositoryService bean work with Xml, the only change required is, to modify the bean reference in the ref tag to a bean of type XmlRepository class.

This is how Dependency Injection (DI) helps in reduce coupling between components.

Sample code can be found here.