How it works
The explanation, with examples you can run.
Describing beans
There are two common ways to tell the container about an object. Component scanning finds classes annotated with @Component (or its specialisations @Service, @Repository, @Controller) under the package of your @SpringBootApplication class. A @Bean method in a @Configuration class is for objects you can't annotate, such as a client from a library.
@Servicepublic class OrderService { private final OrderRepository orders; private final Clock clock; // One constructor: no @Autowired needed public OrderService(OrderRepository orders, Clock clock) { this.orders = orders; this.clock = clock; }} @Configurationclass TimeConfig { @Bean Clock clock() { return Clock.systemUTC(); }}When the context starts it sees that OrderService needs an OrderRepository and a Clock, finds (or first creates) a bean of each type, and calls the constructor. Each object made this way is a bean.
Why constructor injection
Spring can also inject into fields (@Autowired private Foo foo) or setters, but the constructor is the better default:
- The fields can be
final, so the object is complete the moment it exists. - A unit test can call the constructor with fakes; no container needed.
- A constructor with eight parameters is a visible sign the class does too much. Eight injected fields hide it.
When there are several candidates
Matching is by type. If two beans implement the same interface, the container refuses to guess:
@Bean @PrimaryPaymentGateway stripe() { return new StripeGateway(); } @BeanPaymentGateway paypal() { return new PayPalGateway(); } // Gets stripe (the primary) unless it asks by namepublic CheckoutService(@Qualifier("paypal") PaymentGateway gateway) { ... }You can also ask for List<PaymentGateway> or Map<String, PaymentGateway> to receive all of them, which is a neat way to build plug-in style strategies.
Fail fast
Because the whole graph is built at start-up, a missing bean, an ambiguous type or a cycle stops the application with a message naming the class and the parameter. That is a feature: a broken wiring diagram never reaches production traffic. Since Spring Boot 2.6 circular references are rejected by default too; if two services need each other, a third class usually wants to exist.
Check yourself
3 questions. Get them all right to finish this topic.
0 of 3 right so far. Get all three to finish this topic.