In the previous tutorial we got the gist of the Spring Boot. Before proceeding further let's discuss Dependency Injection.
What is Dependency Injection (DI)?
When writing a complex Java application, application classes should be as independent as possible of other Java classes to increase the possibility to reuse these classes and to test them independently of other classes while doing unit testing. Dependency Injection helps in gluing these classes together and keeping them independent at the same time.
Dependency Injection design pattern allows us to remove the hard-coded dependencies and make our application loosely coupled, extendable and maintainable.
For example, 'DEPENDENCY' means class A is dependent on class B. 'INJECTION' signifies that class B will get injected into class A by the IoC (Inversion of Control).
Dependency injection can happen in the way of passing parameters to the constructor or by post-construction using setter methods.
In DI mainly three classes are involved:
- Client Class: This is dependent on service class. In above example A is the Client class.
- Service Class: This provides service to the client class. In above example B is the Service class.
- Injector Class: It is responsible for injecting Service class objects into the client class.
Types on Dependency Injection:
In general, dependency injection can be done in three ways:
1). Field Injection: To do this we need to declare the variable(hopefully private) and then annotate it with @Autowired. e.g:
@Autowired
private ProvidentFund providentFund;
2). Constructor Injection: In this we let the Spring Container inject the dependencies directly through the constructor. e.g:
@RestController
public class EmployeeInformation {
private final ProvidentFund providentFund;
public EmployeeInformation(ProvidentFund providentFund){
this.providentFund = providentFund;
}
}
3). Setter Injection: It's quite similar to the Field Injection, but here we need to annotate the setter with @Autowired tag. This is rarely used.
private ProvidentFund providentFund;
@Autowired
public void setProvidentFund(ProvidentFund providentFund){
this.providentFund = providentFund;
}
Please note:
- The field injection uses reflection to set the values of private variables. Constructor injection happens at the time of creating the object itself. Whereas the setter Injection uses setters to set the value.
- Constructor injection is more reliable than field/setter injections because of immutable variables.
- Field/setter injection provides the freedom to add unlimited new dependencies. However the constructor injection is more aligned to the Open-Closed principle of SOLID principles.
- Cyclic dependencies can easily be detected and fixed when we are Constructor Injection. Whereas other two injections failed to detect cyclic dependencies.
- Performance wise field/setter injections are faster because each object can be created independently and dependency is injected later using reflection/setter. In case of constructor injection, all the beans have to be created in the correct order of dependencies which increases the startup time of the application.
Because of reliability and strict behavior, constructor injection is always the first choice. In case the constructor injection is not possible (e.g may be when we want to avoid circular dependencies) we can use field injection.
A couple of months ago, I had a lengthy discussion with one of my ex-colleagues about constructor injection for required dependencies and field injection for optional.
Well, I feel mostly optional dependencies result in a bad design. Anyone can randomly add multiple dependencies by calling it optional. This will eventually reduce the quality of the overall code.
If you enjoy our content and want to support us, please consider donating via gpay, phonepay or paytm on +91 9920600280. Also, I’d appreciate if you’d buy me a coffee☕
Keep learning and growing!
-K Himaanshu Shuklaa..
No comments:
Post a Comment