Spring's Annotation Type Required deprecation
There are three ways to inject a bean via annotation:
Field injection
@Autowired
private FooService fooService;
Setter injection
private FooService fooService;
@Autowired
public void setFooService(FooService fooService) {
this.fooService = fooService
}
Constructor injection (this is the mentioned replacement)
private final FooService fooService;
@Autowired
public MyComponent(FooService fooService) {
this.fooService = fooService;
}
As you can see, the only way to declare your Service final
is by using the constructor injection, which replaces the @Required
annotation because it forces the user of your class to instantiate it with the required services. The user does not have to be Spring, it could be a simple unit test as well.
You should use constructor injection for mandatory dependencies and setter injections for optional dependencies instead of field injection. Some reasons why:
- It makes it clear to everybody which dependencies are required
- It makes testing easier
- You can make your objects immutable
Further reading:
- http://olivergierke.de/2013/11/why-field-injection-is-evil/
- https://www.vojtechruzicka.com/field-dependency-injection-considered-harmful/
- https://spring.io/blog/2007/07/11/setter-injection-versus-constructor-injection-and-the-use-of-required/
Update: non-annotated constructor injection
As one commentator was wondering about a final
field annotated with @Autowired
while the constructor was not annotated:
If a class only declares a single constructor to begin with, it will always be used, even if not annotated.
https://docs.spring.io/spring-framework/docs/5.2.5.RELEASE/javadoc-api/org/springframework/beans/factory/annotation/Autowired.html ("Autowired Constructors")
But even though it is not necessary to annotate the constructor in this case, I would still do it: it documents the code and if anyone will ever add another (non-annotated) constructor, the code will still work.