Spring Boot: From Basics to Production · Spring Core and Spring Boot Fundamentals
Dependency Injection and Beans
Let Spring create and wire your components through constructors.
Spring's IoC container creates objects called beans and injects their dependencies. Mark classes with stereotypes (@Component, @Service, @Repository, @RestController) or declare beans with @Bean methods in @Configuration classes (useful for third-party types). Prefer constructor injection with final fields — dependencies are explicit, immutable and easy to test. With a single constructor, no @Autowired is needed.
public interface PaymentGateway {
PaymentResult charge(Money amount, String token);
}
@Service
public class CheckoutService {
private final OrderRepository orders;
private final PaymentGateway payments;
public CheckoutService(OrderRepository orders, PaymentGateway payments) { // constructor injection
this.orders = orders;
this.payments = payments;
}
public Order checkout(Cart cart, String token) {
var result = payments.charge(cart.total(), token);
return orders.save(Order.paid(cart, result.reference()));
}
}
@Configuration
class PaymentConfig {
@Bean
PaymentGateway paymentGateway(StripeProperties props) {
return new StripeGateway(props.apiKey());
}
}
Common pitfalls
- Field injection (
@Autowired private Foo foo;) — hides dependencies and complicates tests. - Circular dependencies between services (a design smell; Boot fails fast by default).
- Multiple beans of the same type without
@Primaryor@Qualifier.
Key points
- Beans are container-managed objects
- Constructor injection with final fields
- @Bean for third-party classes
Further reading: Spring: Dependency injection
Practice questions
Why is constructor injection preferred over field injection?
Answer
Dependencies are explicit and final, objects can't be created half-initialized, tests can instantiate classes with plain new, and circular dependencies are detected.
How do you resolve two beans implementing the same interface?
Answer
Mark one @Primary, or inject a specific one with @Qualifier("name"), or inject List<Interface>/Map<String, Interface> to get all.
Open in the app to mark lessons complete, take notes and track your progress.