As I know, field injection
is not recommended. Should use constructor
instead.
What I'm trying to do here is using @Autowired
in the constructor of the base class, and make it accessible for all the subclasses. In some subclasses, I also need some specific beans to be @Autowired
from their constructors. Demo code is as following:
Base class:
public abstract class Base {
protected final MyDemoService myDemoService;
@Autowired
public Base(MyDemoService myDemoService) {
this.myDemoService = myDemoService;
}
}
Inherited(sub) class:
public class Sub extends Base {
private final MySubService mySubService;
@Autowired
public Sub(MySubService mySubService) {
this.mySubService = mySubService;
}
}
This will give me a 'no default constructor' error.
It's similar to the question: similar question and answer, but it doesn't work here.
I have dived into this for a while, I found this article about dependency injection
: further read
I'm thinking is the Setter Injection
a right way for my question?
Setter injection:
public abstract class Base {
protected MyDemoService myDemoService;
@Autowired
public void setMyDemoService(MyDemoService myDemoService) {
this.myDemoService = myDemoService;
}
}
I'm new to Java Spring Boot, and want to get some expertise advise from you guys. Any discussion will be highly appreciated!
Certainly, using @Service annotation on abstract classes doesn't have any effect in Spring.
You can simply extend the abstract class with another class, and use @Component in the subclass.
For example, there are two POJO classes Customer and Person. The Customer class has a dependency on the Person. @Autowired annotation is optional for constructor based injection. Here, the person object from the container is passed to the constructor while creating the Customer object.
You don't. You only declare the beans which have a concrete subclass of that abstract class. This link of the spring documentation could help you!
The code that you provide won't compile. As long as in your base class you don't have the default constructor, you should call super(MyDemoService)
in child.
Inherited(sub) class:
public class Sub extends Base {
private final MySubService mySubService;
@Autowired
public Sub(MySubService mySubService, MyDemoService myDemoService){
super(myDemoService);
this.mySubService = mySubService;
}
}
Or, if MySubService
is an implementation of MyDemoService
@Autowired
public Sub(MySubService mySubService){
super(mySubService);
}
As long as your field MyDemoService myDemoService
in abstract class is protected
you can use it in subclasses.
If you have multiple implementation of MyDemoService
, than you have to use @Qualifier
as described in the answer that you have mentioned.
public Sub(@Qualifier("MySubService") MyDemoService mySubService){
super(mySubService);
}
Don't use field injection, use constructor injection calling back to super constructors as appropriate.
Constructor injection ensures your object is properly populated before instantiation, setter injection does not and makes code more bug prone (not another nullpointer bug....)
If you are concerned about the extra code you have to write then use Project Lombok to let Lombok generate the constructor code for you as described here Why field injection is evil
By the way as of Spring 4 if you only have a single constructor in your class you don't need @Autowired on the constructor.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With