There are three ways to implement DI with @Component annotation: constructor-based injection, setter-based injection, and field-based injection. This article is talking about the different implementations.
Constructor Injection
Before Spring 4.3, we had to add an @Autowired
annotation to the constructor. With newer versions, this is optional if the class has only one constructor.
1 |
|
When we have a class with multiple constructors, we need to explicitly add the @Autowired
annotation to any one of the constructors so that Spring knows which constructor to use to inject the dependencies.
1 |
|
Setter Injection
Spring will find the @Autowired
annotation and call the setter to inject the dependency.
1 |
|
Field Injection
1 |
|
What will happen if we add @Autowired
to both, a field and a setter? In this case, Spring injects dependency using the setter injection method. This is bad practice since it makes the code less readable.
1 |
|
Why constructor Injection
Identifying Code Smells
Constructor injection helps us to identify if our bean is dependent on too many other objects. If our constructor has a large number of arguments this may be a sign that our class has too many responsibilities. We may want to think about refactoring our code to better address proper separation of concerns.
Preventing Errors in Tests
Constructor injection simplifies writing unit tests. The constructor forces us to provide valid objects for all dependencies. Using mocking libraries like Mockito, we can create mock objects that we can then pass into the constructor.
We can also pass mocks via setters, of course, but if we add a new dependency to a class, we may forget to call the setter in the test, potentially causing a NullPointerException in the test.
Immutability
Constructor injection helps in creating immutable objects because a constructor’s signature is the only possible way to create objects. Once we create a bean, we cannot alter its dependencies anymore. With setter injection, it’s possible to inject the dependency after creation, thus leading to mutable objects which, among other things, may not be thread-safe in a multi-threaded environment and are harder to debug due to their mutability.
Reference: Why You Should Use Constructor Injection in Spring
Thank you for reading!