Card 01/ 07

ConceptDifficulty: Intermediate1 min

Constructor Injection: Why It Is Spring's Default

A class wired through its constructor cannot exist half-built, and every dependency is listed in one place.

Constructor injection means a class receives its dependencies as constructor parameters, and the container supplies them when it creates the bean. Field injection means the container writes them into fields marked @Autowired after the object already exists. Both wire the same objects, and constructor injection is the one to use by default.

The RideService below compiles and runs inside Spring, but a unit test cannot create it without starting a whole Spring container, because there is no constructor a test could call with its dependencies. Every dependency arrives through a field, after the object has been created:

java
@Service
class RideService {
    @Autowired private RideRepository repository;
    @Autowired private PricingClient pricingClient;
    @Autowired private NotificationSender notifier;
    @Autowired private AuditLog auditLog;
    // and two more...
}

What differs is what happens without a container. A class wired through its constructor cannot exist half-built, because Java will not construct it without the arguments: new RideService() with no arguments does not compile. A class wired through fields can be created with every field left null, and it only fails later, wherever a missing dependency is first used.

The constructor also makes the class's needs visible. Six dependencies become six parameters in one list, which a reader sees at once and a test can supply one by one with new; spread over annotated fields, the same six are easy to overlook.

So constructor injection makes a half-wired object impossible, and it puts every dependency in one place where both readers and tests can find it.