Spring supports two flavors of Dependency Injection(DI) - Constructor Injection and Setter Injection. Both approaches essentially achieve the same goal, which is to inject dependencies to a class, but they differ in how the beans are injected.
Constructor Injection involves passing dependencies as arguments to the class constructor, while Setter Injection involves exposing the class properties and providing a setter method to set the properties.
Let’s discuss both approaches in detail.
### Constructor-Based Injection:
Constructor-based injection is done by passing dependencies via class constructor arguments. By making use of constructor injection, we can ensure that all required dependencies are available during object instantiation. It helps in establishing a "tighter coupling" between dependent and dependency classes, thereby allowing for better compile-time checking.
public class Employee {
private Address address;
public Employee(Address address){
this.address = address;
}
// ...
}
Note: This is just an example of how we can use Constructor injection; thereby creating an instance of a class and passing the dependency through the constructor method.
The address of an ‘Employee‘ is injected while creating the instance of the ‘Employee‘. The dependency is satisfied by ‘ApplicationContext‘ during initialization of the ‘Employee‘ class. This approach can be useful in situations where only a single instance of a given class is needed, and where dependencies should be immutable once they have been assigned.
Constructor-based injection is generally preferred as it ensures that the object is in a valid state upon instantiation. Additionally, constructor-based injection also allows us to provide dependencies as read-only properties.
### Setter-Based Injection:
Setter-based injection is done by exposing class properties and providing a corresponding setter method to set the properties. Setters enable the bean properties to be accessed after initialization by the ‘Spring IoC container.‘
public class Employee {
private Address address;
public void setAddress(Address address){
this.address = address;
}
// ...
}
The above example shows how we can use Setter injection to set the ‘Address‘ of an ‘Employee‘. The setter method can be used to inject the dependency separately after the instance of the ‘Employee‘ is created.
Setter injection allows for more flexibility than constructor-based injection, as it allows us to have dependencies that can be modified after an instance of the bean is created. This approach is typically used when objects have optional dependencies, on which the objects can work without. It is also used in cases where there is a need to provide default or initial state for bean properties.
To summarize, Constructor-based injection is preferred due to compile time checking and in-built immutability constraints of constructor parameters, while Setter-based injection is more flexible, allowing for greater modification of dependencies after instantiation. Both have their place in our application, and the choice heavily depends on our use-case or preference.