SpringSpring Core

What is Dependency Injection?

Dependency Injection: It’s a design pattern in which we pass an object as an argument to a method or constructor of a class at run-time, rather than creating the object inside the constructor or method of a class, hence making our code loosely coupled.

Note For Beginers: Don’t worry if you didn’t understand the above description, read till end of this page you will be able to understand everything.

Let’s redefine the above definition in a much more formal way and understand it in a bit more detail.

Dependency Injection is a design pattern where a component is given its dependency at run-time instead of hard-coding the dependency inside the component.

Here component is a class and an object which this class requires is a dependency.

Let’s see an example of an application without dependency injection and then we will compare it with an example of an application with dependency injection and then understand how exactly it solves our problem.

Consider we are building an app using which we can make a phone call.This app can run on a basic phone as well as on a smartphone.

Application without dependency injection.

Download this application ->Download

BasicPhone.java


package com.codegeekslab.devices;

public class BasicPhone {
public void makeCall(int number) {
System.out.println("Calling via Simcard... " + number);
}
}

SmartPhone.java


package com.codegeekslab.devices;

public class SmartPhone {
public void makeCall(int number) {
System.out.println("Calling via WhatsApp..." + number);
}
}

CallingApp.java


package com.codegeekslab.app;

import com.codegeekslab.devices.BasicPhone;

public class CallingApp {

private BasicPhone basicPhone;

public CallingApp() {
basicPhone = new BasicPhone();
}

public void dialNumber(int number) {
basicPhone.makeCall(number);
}

}

Test.java


package com.codegeekslab.test;

import com.codegeekslab.app.CallingApp;

public class Test {

public static void main(String[] args) {

CallingApp app = new CallingApp();

app.dialNumber(1419494494);
}
}

Output


calling via simcard... 1419494494

Explanation of above application.

To make a phone call, CallingApp class is dependent either on BasicPhone or SmartPhone class, So to achieve this in our CallingApp class, we are creating the BasicPhone object in the CallingApp constructor using the new keyword and finally making a call via the BasicPhone object. As we have created BasicPhone inside the CallingApp class it made CallingApp class tightly coupled to BasicPhone class.

The problem with our current design.

The problem with our current tightly coupled design is if in future if I want to upgrade my CallingApp to SmartPhone then I have to modify my CallingApp class by replacing the BasicPhone object with the object of SmartPhone like below.

CallingApp.java


package com.codegeekslab.app;

import com.codegeekslab.devices.BasicPhone;

public class CallingApp {

private SmartPhone smartPhone;

public CallingApp() {
smartPhone= new SmartPhone();
}

public void dialNumber(int number) {
basicPhone.makeCall(number);
}

}

As it is a small application, so modification is less, but consider if we are working on a big application, Imagine at how many places we have to change our code.Let’s understand now how we can solve this problem using Dependency Injection.

The solution of the above problem using Dependency Injection.

Let’s re-write the same application using the Dependency Injection design pattern.

Download this example–>Download

CellPhone.java


package com.geekslab.device;

public interface CellPhone {

public void makeCall(int number);

}

SmartPhone.java


package com.codegeekslab.type;

import com.geekslab.device.CellPhone;

public class SmartPhone implements CellPhone {

@Override
public void makeCall(int number) {
System.out.println("calling via whatsapp..." + number);
}

}

BasicPhone.java


package com.codegeekslab.type;

import com.geekslab.device.CellPhone;

public class BasicPhone implements CellPhone {

@Override
public void makeCall(int number) {
System.out.println("calling via simcard... " + number);
}

}

CallingApp.java

package com.codegeekslab.app;

import com.geekslab.device.CellPhone;

public class CallingApp {
private CellPhone phone;
public CallingApp(CellPhone phone) {
this.phone = phone;
}
public void dialNumber(int number) {
phone.makeCall(number);
}
}

Test.java

package com.codegeekslab.test;

import com.codegeekslab.app.CallingApp;
import com.codegeekslab.type.BasicPhone;

public class Test {
public static void main(String[] args) {
CallingApp app = new CallingApp(new BasicPhone());
app.dialNumber(1419494494);

}
}

Output


calling via simcard... 1419494494

Explanation of above application.

To solve the problem of tight coupling in our previous example, we have created an Interface named as Phone and made our BasicPhone and SmartPhone implement that interface by providing an implementation of makeCall() method.And this time we are not creating any object in the constructor of CallingApp class, Instead we are providing a parameter of type Phone Interface in the constructor of CallingApp class and we will pass the implementation of Phone interface, either basicPhone or SmartPhone at the runtime through our Test Class.

The point is that CallingApp isn’t coupled to any specific implementation of Phone. Now in future, if I want to upgrade to SmartPhone, I just have to pass SmartPhone object in the constructor of CallingApp and I don’t have to do any modification in my real application.That’s the key benefit of DI — Loose coupling.

Instead of the constructor of CallingApp, you can also use the setPhone method, of CallingApp to achieve dependency injection like this.

CallingApp.java


package com.codegeekslab.app;

import com.geekslab.device.CellPhone;

public class CallingApp {

private CellPhone phone;

public void setPhone(CellPhone phone) {
this.phone = phone;
}

public void dialNumber(int number) {
phone.makeCall(number);
}

public CellPhone getPhone() {
return phone;
}

}

Test.java


package com.codegeekslab.test;

import com.codegeekslab.app.CallingApp;
import com.codegeekslab.type.BasicPhone;

public class Test {

public static void main(String[] args) {

CallingApp app = new CallingApp();
app.setPhone(new BasicPhone());
app.dialNumber(1419494494);

}
}

Output


calling via simcard... 1419494494
.
So by above examples, we can say that “Dependency” is an object which we want to pass to a method or constructor and “Injection” is a process of passing the object into a method or constructor.

So as said in the description It’s a design pattern in which we pass a dependent object ( new BasicPhone() ) as an argument to a method setPhone(CellPhone phone) or constructor( CallingApp(Phone phone) ) of a dependent class(CallingApp) at run-time (CallingApp smartPhone = new CallingApp(new BasicPhone()); ) rather than creating the depending object inside the constructor or method of a dependent class, hence making our code loosely coupled.

Types of Dependency Injection:

  1. Constructor Injection.
  2. Setter Injection.

Constructor Injection: It’s a type of dependency injection where we pass the dependent object in the constructor of a dependent class.

CallingApp.java


package com.codegeekslab.app;

import com.geekslab.device.CellPhone;

public class CallingApp {

private CellPhone phone;

public CallingApp(CellPhone phone) { // CONSTRUCTOR INJECTION
this.phone = phone;
}

public void dialNumber(int number) {
phone.makeCall(number);
}

public CellPhone getPhone() {
return phone;
}

}

Example: In our above example in which we passed the object BasicPhone class in the constructor of CallingApp class was also an example of constructor injection.

Setter Injection: It’s a type of dependency injection where we pass the dependent object in the Setter method of a dependent class.

Same like before where we passed the object in the set method (setPhone) was also an example of setter injection.

CallingApp.java


package com.codegeekslab.app;

import com.geekslab.device.CellPhone;

public class CallingApp {

private CellPhone phone;

public void dialNumber(int number) {
phone.makeCall(number);
}

public CellPhone getPhone() {
return phone;
}

public void setPhone(CellPhone phone) {
this.phone = phone;
}

}

Here instead of passing the dependent object, in this case BasicPhone object  into the Setter method which is setPhone() method of CallingApp class.

Till now the examples which we have seen of Dependency Injection were implemented using Java.Now we will see how to implement all the above examples of Dependency Injection using Spring Framework and see how easily we can implement Dependency Injection with the spring framework and what other benefits the Spring Framework puts on the table.

Dependency Injection in Spring Framework – Dependency Injection can be achieved by Spring Framework using XML configuration, pure JAVA based configuration and implicit bean discovery with Autowiring.

Methods to implement Dependency Injection:

  1. Explicit configuration in XML.
  2. Explicit configuration in JAVA.
  3. Implicit bean discovery and Autowiring.

These are 3 methods to implement dependency injection using spring framework, In our Next tutorial we will understand all these 3 methods on by one in detail.

One thought on “What is Dependency Injection?

Leave a Reply

Your email address will not be published. Required fields are marked *