Inversion of Control(IoC) and Dependency Injection(DI) In JAVA(SPRING)

Satyendra Kumar Gupta
5 min readJun 13, 2021

In this article, we will see about the concepts of Inversion of Control(IoC) and Dependency Injection(DI), as well as take a look at how these are implemented in the Spring framework.

Introduction: Inversion of Control (IoC) and Dependency Injection (DI), related to each other, The main goal of the Inversion of control and Dependency Injection is to remove dependencies of classes in our application. This makes the system more decoupled maintainable and loosely coupled. In Spring core, the core container module provides essential functionality. The BeanFactory, ApplicationContext is a component of the core container and the Inversion of Control (IoC) pattern is applied by BeanFactory or ApplicationContext. Inversion of Control is used to separate an application’s configuration and dependency specification from the actual application code and it is achieved by Dependency Injection.

Inversion of Control (IoC): Inversion of Control is also known as dependency injection (DI). It is a process whereby objects define their dependencies, that is, the other objects they work with, only through constructor arguments, arguments to a factory method, or properties that are set on the object instance after it is constructed or returned from a factory method. The container then injects those dependencies when it creates the bean. This process is fundamentally the inverse, hence the name Inversion of Control (IoC), of the bean itself controlling the instantiation or location of its dependencies by using direct construction of classes, or a mechanism such as the Service Locator pattern.

Here simple example:

class Calculator{
public int sum(int x, int y){
return 10+20;
}
}

public class Main{
public static void main(String args[]){
Calculator cal=new Calculator();
int result=cal.sum(40,50);
System.out.println(result);
}
}

In the above example you call the sum() method from Main class or anywhere you got result always 30, but notice here you pass as an argument x=40 and y=50, so answer should be 90 but not happened because the control of Calculator class it self. But if you change the flow of the program the control goes to outer class, I mean Main Class, please see the below example.

class Calculator{
public int sum(int x, int y){
return x+y;
}
}

public class Main{
public static void main(String args[]){
Calculator cal=new Calculator();
int result=cal.sum(40,50);
System.out.println(result);
}
}

Here you change the flow of the program, so that the control of the Calculator class comes under the Main class, If you pass what value like x=40 and y=50, then you got a result as a 90. That concept knows as Inversion of Control.

Advantage Of Inversion of Control(IoC):

  • Better clarity of the code
  • More simple structure of the application
  • Re-usability of classes
  • Better test-ability

Disadvantage Of Inversion of Control(IoC):

  • Affect the speed of application
  • If the developer not familiar with the principle of IoC, It may initially be difficult to understand.

Dependency Injection(DI):

Dependency injection (DI) is a process whereby objects define their dependencies (that is, the other objects with which they work) only through constructor arguments, arguments to a factory method, or properties that are set on the object instance after it is constructed or returned from a factory method. The container then injects those dependencies when it creates the bean. This process is fundamentally the inverse (hence the name, Inversion of Control) of the bean itself controlling the instantiation or location of its dependencies on its own by using direct construction of classes or the Service Locator pattern.

A single project or single application has many classes and these are dependent on each other directly or indirectly.

Here Bike depends on keys, fuel, Engine, and also other factors.

So understanding this concept using practically.

Main.java(Main class)package com.spring.ioc;import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
class Keys{
public void run(Engine key){
key.start();
}
}
public class Main {
public static void main(String[] args) {
ApplicationContext context=new ClassPathXmlApplicationContext("file:src/main/java/com/spring/ioc/iocconfig.xml");
Engine key=(Engine) context.getBean("engine");
new Keys().run(key);
}
}
Engine Interfacepackage com.spring.ioc;

public interface Engine {
public void start();
}
Bike.java (Bike class)package com.spring.ioc;
public class Bike implements Engine{
@Override
public void start() {
System.out.println("Bike has been started");
}
}
XML file (bean.xml)<?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 class="com.spring.ioc.Bike" id="engine"/></beans>

In the above example, the Bike depends on the Engine. Without an Engine bike, a not run. So I can say the Bike depends on the Engine for a running.

Depending on injection achieve by XML configuration or java annotation.

Dependency Injection in Spring can be achieved through constructors, setters, or fields.

Constructor Dependency Injection: In this injection, Dependency Injection will be injected with help of the Constructor of class. It is done through the bean configuration file using the <constructor-arg> tag in the bean file.

Example:

Test Class
package com.spring.constructerInjection;

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

public class Test {
public static void main(String[] args) {
ApplicationContext context=new ClassPathXmlApplicationContext("file:src/main/java/com/spring/constructerInjection/constructerinjection.xml");
Person person=(Person) context.getBean("person");
System.out.println(person);
}
}
Person Class
package com.spring.constructerInjection;

public class Person {
private int id;
private String name;
private Helper help;

public Person(int id, String name,Helper help) {
this.id = id;
this.name = name;
this.help=help;
}

@Override
public String toString() {
return this.id+" : "+this.name+" {" +this.help+" }";
}
}
Helper Class
package com.spring.constructerInjection;

public class Helper {
String name;

public Helper(String name) {
this.name = name;
}

@Override
public String toString() {
return this.name;
}
}
XML file (bean.xml)
<?
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 class="com.spring.constructerInjection.Helper" name="help">
<constructor-arg value="Helle helper class"/>
</bean>
<bean class="com.spring.constructerInjection.Person" name="person">
<constructor-arg value="100" type="int"/>
<constructor-arg value="ABC"/>
<constructor-arg ref="help"/>

</bean>
</beans>

In the above example, dependency injects done by the constructor.

Setter Dependency Injection: In this injection, Dependency Injection will be injected with help of the setters method of the class. It is done through the bean configuration file using the ref tag in the bean file.

Example:

Test Classpackage com.spring.ref;

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

public class Test {
public static void main(String[] args) {
ApplicationContext context=new ClassPathXmlApplicationContext("file:src/main/java/com/spring/ref/ref.xml");
A a=(A) context.getBean("aref");
System.out.println(a.getX());
System.out.println(a.getB().getY());
System.out.println("");
System.out.println(a);
}
}
A Class
package com.spring.ref;

public class A {
private int x;
private B b;

public A() {
super();
}

public A(int x, B b) {
this.x = x;
this.b = b;
}

public int getX() {
return x;
}

public void setX(int x) {
this.x = x;
}

public B getB() {
return b;
}

public void setB(B b) {
this.b = b;
}

@Override
public String toString() {
return "A{" +
"x=" + x +
", b=" + b +
'}';
}
}
B Class
package com.spring.ref;

public class B {
private int y;

public B() {
super();
}
public B(int y) {
this.y = y;
}

public int getY() {
return y;
}

public void setY(int y) {
this.y = y;
}

@Override
public String toString() {
return "B{" +
"y=" + y +
'}';
}
}
XML file (bean.xml)<?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 name="bref" class="com.spring.ref.B">
<property name="y" value="200"/>
</bean>

<bean name="aref" class="com.spring.ref.A">
<property name="x" value="100"/>
<property name="b" ref="bref"/>
</bean>
</beans>

In the above example, dependency injects done by setter methods.

Conclusion:

In this article, we provided the concept of Inversion of Control and Dependency Injection, And also give examples in spring which gives for better understanding.

Thanks.

--

--