Spring Dependency Injection
There are three ways to inject dependencies into beans in Spring, listed below. In this post we’ll quickly go over the three ways of injection.
- Constructor
- Setter
- Field
Constructor-based injection
Constructor-based injection is typically the best way to go about injecting dependencies into beans. With constructor-based injection we’re able to enforce two main ideas,
- Missing consturctor-based beans will cause a BeanDefinitionException if the dependency is missing
- We’re able to make all constructor-based beans threadsafe by assigning them as
private final
class variables (more on this in a later blog post).
Lets see constructor-based injection in action.
@Service
public class ExampleService {
private final ExampleConstructorDependency exampleConstructorDependency;
@Autowired // As of Spring 4.3 this is no longer needed
public ExampleService(ExampleConstructorDependency exampleConstructorDependency) {
this.exampleContructorDependency = exampleConstructorDependency;
}
}
Setter-base injection
The second way to inject dependencies into beans is by using setter-based injection. Setter-based injection utilizes the typical setX
to inject the dependency. Spring recommends utilizing setter-based injection when you’re injecting optional dependencies.
@Service
public class ExampleService {
private ExampleSetterDependency exampleSetterDependency;
@Autowired
public void setExampleSetterDependency(ExampleSetterDependency exampleSetterDependency) {
this.exampleSetterDependency = exampleSetterDependency;
}
}
Field-based injection
The thrid way to inject dependencies into beans is by using field-based injection. Field-based injection is the simpliest and cleanest looking but it comes with some heavy drawbacks that make it very frowned upon.
- Utilizing Java reflection to inject the dependencies which is costlier and riskier than constructor or setter injection
- Vastly reduces ability to properly test the bean
- Adding dependencies becomes so easy that you could forget about Single Responsibility Principle and pile dependencies into a single bean
@Service
public class ExampleService {
@Autowired
private ExampleFieldDependency exampleFieldDependency;
}
Conclusion
In my daily work we have a team standard that all dependencies must be injected via constructor-based injection and all dependencies must be private final
. This standard allows us to know that we’re always going to be threadsafe in our dependencies and we’re going to be consistent across all of the applications we manage. This directive doesn’t work for all teams, which is totally fine, but the one thing I would stress is if you or your team is using field-based injection, have them switch to atleast setter-based injection. It maybe a bit uglier but you won’t run into any of the multiple field-based injecttion drawbacks.