Constructor injection

Spring Boot · lesson 5 of 39 · 3 min read

Wire dependencies the way the Spring team recommends, and see why field injection loses.

Open this lesson in the learning hub

Key points

  • Ask for collaborators as constructor parameters. Spring supplies a matching bean for each one.
  • A class with a single constructor needs no @Autowired at all. Spring infers it.
  • Fields can then be private final — the object is fully built and immutable from birth.
  • Field injection (@Autowired on a field) hides dependencies and cannot be set in a plain unit test.
  • A long constructor is honest feedback: the class has too many jobs. Split it.
  • For an optional dependency use Optional<T> or @Nullable rather than a second constructor.

Example

import org.springframework.stereotype.Service;

@Service
public class OrderService {

    private final OrderRepository orders;
    private final PaymentClient payments;

    // Single constructor -> @Autowired is optional and usually omitted.
    public OrderService(OrderRepository orders, PaymentClient payments) {
        this.orders = orders;
        this.payments = payments;
    }

    public Order place(Order order) {
        payments.charge(order.total());
        return orders.save(order);
    }
}

// In a unit test there is no Spring at all:
// new OrderService(fakeRepo, fakePayments)

Constructor injection gives you final fields, honest dependencies and testable classes.

This is a reading copy. The full lesson — with the visual explainer, the interactive lab and a Run button for the code — lives in the Spring Boot course, and every lesson in it is listed on the Spring Boot contents page.