Categories
Java

What is IoC and DI in Java

What is Inversion of Control?

As the name suggests, IoC is to Invert the control flow of a program. It is an Idea to Decouple/remove dependencies of the object and provide control to another layer(XML, Java Class, Properties,…) to instantiate required Objects.

For more understanding on the above definition I’m adding below example code and diagram.

Example 1 :

public class TraditionalClass {
	private DependentClass dependentClass;
	public TraditionalClass() {
		dependentClass = new DependentClass();
	}
}
Figure 1 : Traditional Approach in Java

In the above example, TraditionalClass is creating a DependentClass object for its use and makes tight coupling with DependentClass. 

Example 2 : 

public class IocClass {
	private DependentClass dependentClass;
	
	public IocClass(DependentClass dc) {
		dependentClass = dc;
	}
}

Figure 2 : Inversion of Control in Java

In the above example, IocClass is not creating its Dependent Objects rather some other Class or Framework will create its object and pass it to its constructor to us. This made the above Program Inverting the control of it.

To achieve IoC we can use many proven design principles like Service Locator and Dependency Injection. 

What is Dependency Injection?

It is a Design pattern with the idea to separate object creation logic to a specific layer and inject it to the required class. 

Dependency Injection pattern will change binding on Objects at Compile time to Run time. Hence we can reusable the class more than before. Unit testing also easy to perform. 

There are three form of DI :

  1. Constructor Injection
  2. Setter Injection
  3. Interface Injection

Let we see the Traditional approach of creating and instantiating the object first and then we will go to DI concepts for better understanding.

Traditional Approach :

In the below example our objective is to take a list of Employees from Database and manipulate it. In this example I’m just calculating the total number of employees in a list. 

In the below example our objective is to take a list of Employees from Database and manipulate it. In this example I’m just calculating the total number of employees in a list. 

Step 1 : Starter Class
public class EmployeeStartupClass {
	public static void main(String[] args) {
		EmployeeController controller = new EmployeeController();
		int count = controller.employeesCount();
		System.out.println("Count : "+count);
	}
}

EmployeeStartupClass is a startup class to kick start our application to run as we need. This is a simple Java application so I used the main method as the entry point of the program. 

This class will call controller class method and print the count of the employees. 

Step 2 : EmployeeController
public class EmployeeController {
	private EmployeeService employeeService;

	public EmployeeController() {
		employeeService = new DBEmployeeServiceImpl();
	} 
	
	public int employeesCount() {
		List<Employee> listOfEmployees = this.getEmployeeService.getAllEmployees();
		return listOfEmployees.size();
	}
	
	public EmployeeService getEmployeeService() {
		return employeeService;
	}

	public void setEmployeeService(EmployeeService employeeService) {
		this.employeeService = employeeService;
	}
}

EmployeeController class is a Controller that will be used to get a total number of employees from a service class. If you want more features you can add another method saying employeesByCity() to get employees specific to the city in the same controller. 

Step 3 : EmployeeService
public interface EmployeeService {
	List<Employee> getAllEmployees();
}

Services classes should be implemented by an Interface to control what are the features it can have. So we have an EmployeeService interface here.

Step 4 : DBEmployeeServiceImpl
public class DBEmployeeServiceImpl implements EmployeeService{
	@Override
	public List<Employee> getAllEmployees() {
		// get Employee list from DB
		return employeesList;
	}
}

DBEmployeeServiceImpl is an implementation of EmployeeService, it will connect to the Database and get all the Employees list and return it to the EmployeeController class. 

Step 5 : Employee POJO Class
public class Employee {
	private int empID;
	private String empName;
	private int empAge;
	private String role;
	public int getEmpID() {
		return empID;
	}
	public void setEmpID(int empID) {
		this.empID = empID;
	}
	public String getEmpName() {
		return empName;
	}
	public void setEmpName(String empName) {
		this.empName = empName;
	}
	public int getEmpAge() {
		return empAge;
	}
	public void setEmpAge(int empAge) {
		this.empAge = empAge;
	}
	public String getRole() {
		return role;
	}
	public void setRole(String role) {
		this.role = role;
	}
}

Employee is a Plain Old Java Object(POJO) class to store values from DB and use it later. 

In the above example everything will look fine, when you run the program you can see the total number of employees count will be printed in Starter class. 

Service class is responsible to get Employee details to your controller class and controller class is responsible to manipulate the data and present what needs to the user from the Employee list. Programming logic and business layer will be adopted by Controller classes. 

If your application is getting popular and you started selling it to more clients, assume if one of your clients has Employee details in Excel and not in any Database. What can we do in this situation? We have to modify our controller class or add a new Service class to read data from Excel. 

Adding a new service class or service method is a good idea because we have all the business logic in the Controller class already.

Now say for example you are adding a new class called ExcelEmployeeServiceImpl implementing EmployeeService. I will get all the employee lists from Excel and return into the EmployeeController class as DBEmployeeServiceImpl class did in the above example. 

Step 6 : ExcelEmployeeServiceImpl
public class ExcelEmployeeServiceImpl implements EmployeeService{
	@Override
	public List<Employee> getAllEmployees() {
		// get Employee list from Excel
		return employeesList;
	}
}

Now how are you going to initialize the new ExcelEmployeeServiceImpl object in the Controller class? 

You are having one Controller class and two different service classes both are needed in some specific time(not simultaneously). It is not a good idea to create a new controller class for Excel data alone. You can see there is a tight contract between EmployeeController and DBEmployeeServiceImpl class, it is compile-time binding/tight coupling. 

To solve this issue and make Controller class more reusable, Dependency Injection pattern is a right choice in Java. 

Dependency Injection Approach : 

As we said earlier Object binding will be at Run time in DI. We are going to create a Dependent object in Assembler and pass it to the controller to use. 

In the below example we will see how DI can be implemented in the above example without losing any features.

Constructor Injection Example : 

Constructor Injection means to Inject or Pass dependent objects as a Constructor argument.

Step 1 : Change in Controller class
public class EmployeeController {
	private EmployeeService employeeService;

	public EmployeeController(EmployeeService employeeService) {
		this.employeeService = employeeService;
	} 
	
	public int employeesCount() {
		List<Employee> listOfEmployees = this.getEmployeeService().getAllEmployees();
		return listOfEmployees.size();
	}
	
	public EmployeeService getEmployeeService() {
		return employeeService;
	}

	public void setEmployeeService(EmployeeService employeeService) {
		this.employeeService = employeeService;
	}
}

Looking at the code above, I have removed object creation from Constructor and added a parameter to receive the same EmployeeService object to instantiate and use it in employeesCount() method. Now I can create a DBEmployeeServiceImpl object or ExcelEmployeeServiceImpl object from outside of the class and pass it here. Hence if a client needs Excel data to be loaded we can pass ExcelEmployeeServiceImpl object or else we can pass DBEmployeeServiceImpl object without breaking any feature. EmployeeController will become a more reusable class and unit testing friendly.  

I shall show you the assembler I used here to enable DI. 

Step 2 : Introducing Assembler Class
public class EmployeeAssembler {
	public void assembleObjects() {
		EmployeeService employeeService = null;
		//Below code will inject DBEmployeeServiceImpl
		employeeService = new DBEmployeeServiceImpl();
		new EmployeeController(employeeService);
		
		//Below code will inject DBEmployeeServiceImpl
		employeeService = new ExcelEmployeeServiceImpl();
		new EmployeeController(employeeService);
	}
}

EmployeeAssembler will take the responsibility to create DB and ExcelEmployeeServiceImpl objects separately and pass it to the EmployeeController constructor.

You can see the assembler class is injecting both the service impl objects one after another. We can restrict the code to pass only one at a time with some conditional statements. 

Setter Injection Example : 

Dependent objects will get created from assembler and pass it to the setter method to initialize at runtime. 

Look at the example for better understanding. 

Step 1 : Modify Controller Class
public class EmployeeController {
	private EmployeeService employeeService;

	public EmployeeController() {
	} 
	
	public int employeesCount() {
		List<Employee> listOfEmployees = this.getEmployeeService().getAllEmployees();
		return listOfEmployees.size();
	}
	
	public EmployeeService getEmployeeService() {
		return employeeService;
	}

	public void setEmployeeService(EmployeeService employeeService) {
		this.employeeService = employeeService;
	}
}

Now i have removed the constructor arguments and object initialization. The setter method of EmployeeService variable will catch the object that is passed from Assembler class and initialize it to the employeeService variable. 

employeesCount() method will use the object as like before and manipulate the employee details normally. 

Step 2 : Modify Assembler class

Let us see the modified Assembler class for Setter Injection.

public class EmployeeAssembler {
	public void assembleObjects() {
		EmployeeService employeeService = null;
		//Below code will inject DBEmployeeServiceImpl
		employeeService = new DBEmployeeServiceImpl();
		new EmployeeController().setEmployeeService(employeeService);
		
		//Below code will inject DBEmployeeServiceImpl
		employeeService = new ExcelEmployeeServiceImpl();
		new EmployeeController().setEmployeeService(employeeService);
	}
}

Here you can see the setter method from EmployeeController is accepting employeeService object. 

That’s all for now on IOC and DI concepts. Please comment your thoughts on this article and share it to your friends if you find this useful.

Thank you for reading!!!

2 replies on “What is IoC and DI in Java”

[…] Dependency Injection pattern is strongly implemented in Spring, hence it is loosely coupled between every Class and layers of your application. For example, you can use Struts MVC Framework in UI Layer, Hibernate DAO in Data Access layer. If you want to change the UI Layer to any other UI Frameworks you just need to change the configuration and little piece of code, that’s the beauty of Spring. […]

Leave a Reply

Your email address will not be published.