Chapter 2 · Practice 1 of 4
Use constructor injection with final fields
Why it matters
Field injection with @Autowired on a private field looks short, but it hides dependencies, makes fields mutable and forces tests to use reflection or a Spring context to set them.
Constructor injection fixes all three:
- Dependencies are visible in the constructor signature.
- Fields can be
final, so the object is fully built before use. - Unit tests call the constructor with fakes, with no Spring at all.
A class with a single constructor needs no @Autowired annotation. If a constructor grows past four or five parameters, that is a sign the class does too much, not a reason to switch back to field injection.
Example
@Service
public class OrderService {
private final OrderRepository orders;
private final PaymentClient payments;
public OrderService(OrderRepository orders, PaymentClient payments) {
this.orders = orders;
this.payments = payments;
}
}