Spring Dependency Injection is a powerful feature of the Spring Framework that enables you to write flexible, modular, and maintainable Java applications. By reducing the complexity of code and providing modularity and flexibility, Spring Dependency Injection is widely used in enterprise applications.
In this article, we will explore the concepts of Dependency Injection (DI) and Inversion of Control (IoC) and how they are implemented in Spring.
What is Dependency Injection?
Dependency Injection is basically the ability of an object to supply the dependencies of another object.
Now what does Dependency mean? Dependency refers to where a class uses certain functionalities of another class.
For example, you have made a class Person and a class Boy, and Boy uses some functionalities of the Person class. It means that Boy has a dependency on the Person class.
The process of creating an object for some other class and letting the class directly use the dependency is called Dependency Injection.
Dependency Injection is based on the Concept of Inversion Control Concept; we will discuss it now.
Here's your problem of the day
Solving this problem will increase your chance to get selected in this company
Skill covered: Programming
How do you create a function in JavaScript?
def myFunction() {}create function myFunction()function myFunction() {}
Choose another skill to practice
Need for Dependency Injection
The following are some points that provide the need for the usage of dependency injection:
Highly Extensible Code Because of the externally injected dependencies, the programmers are able to scale up the application without managing dependencies manually for each function. This makes the process more efficient and helps update the application with far less effort.
Testable Code It helps the programmers write the test cases easily. They can use mock databases with the dependency injection and test it without hindering the actual database.
Reusable Code It helps reuse the logic and implementation of the codes. You can create a plug-and-play kind of module to reuse your codes.
Maintainable Code By using a loosely coupled design, it provides high maintenance to the code. It drastically reduces the cost of ownership.
Inversion of Control It is a form of Inversion of Control. The control here is inverted to a component of high level, for the handling of creation and injection of the dependencies.
What is Spring Dependency Injection?
Spring framework serves as a dependency injection, which is a form of inversion control ( Inversion of Control is a programming principle that inverts the flow of control as compared to traditional control flow). If you start with an application, it might require other classes as well, like helper and utility classes.
So, in basic Java, the application class would instantiate the helper and utility classes and then start using them, increasing the coupling between them.
The application class now depends upon the correct implementation of helper and utility classes, and also, there is no concept of abstraction among the classes.
This makes it difficult to test the application class alone, as it will always instantiate the other two classes.
This is now when the spring dependency injection container comes into the picture.
With the help of spring dependency injection, you will have the same classes to run your application but rather than instantiating and binding the classes; you will have to instruct the spring DI container to do the same for you.
=> This can be done using annotations in the code or using configuration code or XML configuration code.
Example of Spring Dependency Injection
The following is a code example where we make two classes, namely Person and Address.
Here we are injecting a dependency between the Person and Address classes where the Person class has an Address attribute, so the class depends on Address.
Code in Java
Java
Java
public class Person { private Address address;
// Here, we have an attribute that is actually an object of another class public Person(Address address) { this.address = address; }
// Here, we are setting the address attribute. // We are using a setter function to set the dependency, // so it is a Setter Dependency Injection
public void setAddress(Address address) { this.address = address; }
public Address getAddress() { return address;
} } public class Address { private String Street; private String city; private String state; public Address(String street, String city, String state) { this.street = street; this.city = city; this.state = state; }
public String getStreet()
{ return street;
}
public String getCity() { return city; }
public String getState() { return state; }
public void setStreet(String street) { this.street = street; }
public void setCity(String city) { this.city = city; }
public void setState(String state) { this.state = state; } } public class Main { public static void main(String[] args) { // Create an Address object Address address = new Address("123 Elm Street", "Springfield", "IL");
// Create a Person object and inject the Address dependency Person person = new Person(address);
// Print out the Address information from the Person object System.out.println("Street: " + person.getAddress().getStreet()); System.out.println("City: " + person.getAddress().getCity()); System.out.println("State: " + person.getAddress().getState()); } }
You can also try this code with Online Java Compiler
Street: 123 Elm Street
City: Springfield
State: IL
Explanation Here we can clearly see that we are using setter functions to initialize the attributes in the classes, so here is a Setter Dependency Injection because the setter function setAddress() takes care of the address dependency by initializing an object of the address class.
Types of Spring Dependency Injection
There are three kinds of Dependency Injection in Spring boot:
Setter Dependency Injection
Constructor Dependency Injection
Field Dependency Injection
We will explain the Setter and Constructor Dependency injection below:
1. Setter Dependency Injection
In this type, a Setter method provides the class with dependencies. It refers to the @Autowired annotation on the top of the setter method of the class. Let us take an example below.
Let us take an example of the TeacherMasterDetails class below:
import org.springframework.stereotype.Component;
import lombok.Getter;
import lombok.ToString;
import lombok.Setter;
@Component
@Getter
@Setter
@ToString
public class TeacherMasterDetails{
private int teacherID;
private String teacherName;
private String teacherdept;
}
Also, a SchoolMasterDetails class is as follows:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RestController;
@ResstController
public class SchoolMasterDetails{
private TeacherMasterDetails teachmastdetails;
@Autowired
public void setTeachMasterDetails(TeacherMasterDetails teachmastdetails){
this.teachmastdetails = teachmastdetails;
}
@Override
public String toString(){
return "SchoolMasterDetails [teachmastdetails="+teachmastdetails+"]";
}
}
The Autowiring occurs here using the setter method in the SchoolMasterDetails class. The bean object is created for the TeacherMasterDetails class and injected via the setter method in the SchoolMasterDetails class.
2. Constructor Dependency Injection
Here, a class constructor provides dependencies. It refers to the @Autowired annotation on the top of the class constructor.
For example, for the same TeacherMasterDetails class used above, the SchoolMasterDetails class will be as follows:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RestController;
@ResstController
public class SchoolMasterDetails{
private TeacherMasterDetails teachmastdetails;
@Autowired
public SchoolMasterDetails(TeacherMasterDetails teachmastdetails){
this.teachmastdetails = teachmastdetails;
}
@Override
public String toString(){
return "SchoolMasterDetails [teachmastdetails="+teachmastdetails+"]";
}
}
Here, the TeacherMasterDetails class object has been Autowired into the SchoolMasterDetails class constructor. Thus, the bean object for TeacherMasterDetails is injected into the SchoolMasterDetails constructor.
Uses of Spring Dependency Injection
Now let's discuss some uses of Dependency Injection:
Dependency injection is a design pattern that promotes loose coupling between classes by allowing dependencies to be injected from outside of the class.
Dependency injection can be implemented using either constructor injection, setter injection, or interface injection.
Dependency injection promotes code reuse and modularity by separating concerns and allowing components to be easily swapped out.
Dependency injection is a core concept in the Spring framework and is used extensively in Spring-based applications.
Setter Dependency Injection vs. Constructor Dependency Injection
Aspect
Setter Dependency Injection
Constructor Dependency Injection
Definition
Dependencies are injected via setter methods after the object is created.
Dependencies are injected through the constructor at the time of object creation.
Flexibility
Allows dependencies to be changed or reset after the object is created.
Dependencies are immutable after object creation, ensuring consistency throughout the object's lifecycle.
Mandatory Dependency
Optional; if a dependency is not set, it won’t cause a compile-time error, potentially leading to null references.
Ensures all dependencies are provided at creation, preventing object creation if required dependencies are missing.
Ease of Testing
Suitable for testing as dependencies can be modified through setters for specific test cases.
Ensures dependencies are initialized only once, simplifying testing and reducing the need for mock injections.
Object Creation
Object creation and dependency injection are separated, allowing the object to exist even if dependencies are absent.
Requires all dependencies during object creation, which may be a limitation if some dependencies aren't immediately available.
Readability
May lead to cluttered code if multiple setter methods are used, impacting readability.
Provides clear visibility of required dependencies directly in the constructor, improving code readability.
Usage
Preferred when dependencies are optional or can change after object creation.
Preferred for mandatory dependencies that the object requires to function correctly from the start.
Error Detection
Errors may appear at runtime if dependencies are missing, as they aren't set during object creation.
Errors are caught at compile-time if dependencies are missing, providing early feedback during development.
Frequently Asked Questions
Which dependency injection is best in Spring?
We can say that the constructor dependency injection is best in Spring for various reasons. It has better readability, supports immutability, and is state-safe(the object is instantiated to the entire state or not at all).
What type of dependency injection is used in Spring Boot?
In Spring Boot, primarily, Constructor-based dependency injection is used. Here, dependencies are injected using the class constructor. The Spring Framework manages the creation and injection of the dependencies when the dependencies of the class, as constructor parameters, are defined.
What are the advantages of using Spring Dependency Injection?
Spring Dependency Injection simplifies code management by reducing dependencies and improving testability. It allows loose coupling between components, enhances code reusability, and promotes modular design, making applications more flexible and easier to maintain.
Conclusion
Spring Dependency Injection is a very flexible and efficient way of managing dependencies of objects and classes. By allowing objects to be created and wired together dynamically, developers can achieve loose coupling, improved testability, and maintainability in their applications.
You can also consider our Spring Boot Course to give your career an edge over others.