This is a series and it would make a lot of sense if read in a sequence. You can find all the posts under the heading “Spring Beginners to Professionals“. This is the fourth post of the series.
The next important concept is Inversion of Control. In fact, Inversion of Control is the heart of Spring Framework. You might also have heard the short form which is IoC. This post is dedicated for understanding the Inversion of Control in detail.
Inversion of Control
The one core concept which is not optional in Spring is the “Inversion of Control”. Spring and many similar frameworks claim to use Inversion of Control to provide us with an infrastructure to connect all the components in a flexible and plug-gable way.
It is a design pattern which enables assembling or wiring various components into a cohesive application. No application can be built in isolation. It must contain more than one class and these classes in one way or the other are dependent on one another.
For example: A sample web application having three layers web, business and database. The problem posed to developers and architects is to wire these three layers such that the web layer can use the business layer which in turn can use the data access layer.
At first, it seems to be an easy solution. Let us use an example of a two tier application to demonstrate the problem we are trying to solve using Inversion of Control.
A Simple Application
Let us define an imaginary application which displays all the orders placed by a customer.
I write two classes, OrderClient and CSVDataStore which implements a DataStore interface. The responsibility of the OrderClient class is to invoke a method getCustomerOrders(id) of the DataStore with a customer id and publish the results to the user. The responsibility of the CSVDataStore class is to read the data from the underlying CSV file, filter it based on the customer id and supply it to the caller.
Although we have an interface based design, but still someone has to create a concrete instance of the CSVDataStore with a reference variable of type DataStore to actually read the data.
The easiest way is to make the OrderClient class responsible for creating an instance of the CSVDataStore class and assign to a DataStore type variable and use the object to read the values like below:
DataStore store = new CSVDataStore();
List<Order> orders = store.getCustomerOrders(id);
So, here the control for instantiating the correct DataStore object is with the OrderClient object.
Did we miss something?
Everything works fine, until one day I want to change the underlying data store and use a MySQL database instead. The application will fail miserably because the CSVDataStore was capable of reading from a CSV file only.
So, I write a new class MySQLDataStore and make it implement DataStore interface. Still, someone has to create a concrete instance of this class in the OrderClient class to actually make it work. Again the instance of MySQLDataStore can be created by the OrderClient object.
You can notice that the OrderClient object is dependent on two things, the DataStore interface and its related implementation. The desired behavior would be being independent of the implementation. In this scenario, the DataStore module is really not pluggable.
A brilliant idea
By any means if we can make someone else responsible for creating and injecting the right dependent object of type DataStore into the OrderClient object, we will be successful in removing the dependency of DataStore implementations from OrderClient.
You must have guessed that we are talking about inverting the control of injecting the right DataStore dependencies for the OrderClient object and making the client no more responsible for instantiation of the dependent objects.
The Inversion of Control design pattern talks about a container (a separate component), which is responsible for this job. So the control gets inverted and the dependencies gets injected by the container. Therefore, a more specific term for this paradigm or behavior is Dependency Injection.
Few of the benefits of IoC are:
- The IoC design pattern helps in writing cleaner code and decoupling between the components is more effective.
- The objects are freed from the responsibility of looking up and loading their dependent classes.
- The classes become easier to test, because the dependencies are on interfaces or abstract base classes, hence stubbing is easier.
Inversion of Control is a principle which is implemented by many frameworks and programming models. For e.g.: The Service Locator pattern, Event Loops, Schedulers, Callbacks and many more uses this principle.
As we are now equipped with the knowledge of Aspect Oriented Programming, Annotations and Inversion of Control, we are ready to dive deep into the Spring Framework. Look out for the next post which describes the Spring Framework and its internals.
Here is the link for Martin Fowler’s post on Dependency Injection. This is a lengthy post, but highly recommended for people trying their hands on IoC.