Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

what is the best way to autowire parent class field in spring?

Tags:

java

spring

When I use spring framework, I find something that should be extract, for example, the service component (or member variable that is autowired). Code show as below:

abstract class Payment {

    PaymentService paymentService;

    void setPaymentService(OrderPaymentService paymentService) {
        this.paymentService = paymentService;
    }

}    

@Component
public class CancelPayment extends Payment{
    private OtherService2 otherSerivce2;

    @Autowired
    @Override
    public void setPaymentService(PaymentService paymentService) {
        super.setPaymentService(paymentService);
    }

    @Autowired
    public CancelPayment(OtherService2 s2) {
        this.otherSerivce2 = s2;
    }
}

@Component
public class CreatePayment extends Payment{
    private OtherService1 otherSerivce1;

    @Autowired
    @Override
    public void setPaymentService(PaymentService paymentService) {
        super.setPaymentService(paymentService);
    }

    @Autowired
    public CreatePayment (OtherService1 s1) {
        this.otherSerivce1 = s1;
    }
}

As you can see, I use setter injection in each child class. Is this a better practice than autowire their parent's member variable?

like image 247
Lauda Wang Avatar asked Apr 03 '19 03:04

Lauda Wang


Video Answer


1 Answers

Here are DI guidelines by Spring team:


A general guideline, which is recommended by Spring (see the sections on Constructor-based DI or Setter-based DI) is the following:

  • For mandatory dependencies or when aiming for immutability, use constructor injection

  • For optional or changeable dependencies, use setter injection

  • Avoid field injection in most cases


Now if you are sure you will use PaymentService I would suggest you to use constructor injection in your abstract class like this so object won't instantiate without dependency, also making it more immutable, clearer and thread safe:

abstract class Payment {
    PaymentService paymentService;


    public Payment(OrderPaymentService paymentService) {
        this.paymentService = paymentService;
    }
}

Then you can simply call super on your extended classes like this:

@Component
public class CreatePayment extends Payment{
    private OtherService1 otherSerivce1;

    @Autowired
    public CreatePayment(PaymentService paymentService) {
        super(paymentService);
    }
}

This simply allows you to inject parent class using constructor (if paymentService is mandatory).

like image 79
noname Avatar answered Nov 15 '22 14:11

noname