Dependency Injection
Think of Spring Boot Dependency Injection as a marionette master that knows exactly which strings to pull to make your objects dance together.
Pre-Spring
// Without DI
public class CheckoutController {
private PaymentService paymentService = new PaymentService(
new FraudCheck(),
new Database(),
new EmailService()
//more things that PaymentService may need...
);
}
Every new
is a commitment. Want to test it? You get the entire dependency tree. Need a mock database? Rewrite all constructors.
Spring's IoC Container
Imagine you're a chef in a kitchen. Instead of running to the farm for eggs, the dairy for milk, and the mill for flour, you shout "I need ingredients!" and they appear on your counter. **That's Spring's IoC (Inversion of Control) Container—**your personal assistant for Java objects.
How It Works
- Component scan: Spring scans your code for classes marked with annotations such as
@Component
,@Service
,@Controller
. - Beans creation: Spring instantiates these classes as "beans" (managed objects) and stores them in its container.
- Dependency injection: When you need a bean, Spring automatically gets it for you from the container.
Ways to Do Dependency Injection
Field Injection
@RestController
public class CheckoutController {
@Autowired
private PaymentService paymentService;
//Controller logic
}
Setter Injection
@RestController
public class CheckoutController {
private PaymentService paymentService;
@Autowired
public void setPaymentService(PaymentService paymentService) {
this.paymentService = paymentService;
}
//Controller logic
}
Constructor Injection
@RestController
public class CheckoutController {
private final PaymentService paymentService;
public CheckoutController(PaymentService paymentService) {
this.paymentService = paymentService;
}
//Controller logic
}
Constructor injection is the recommended approach:
- No nulls – Your dependencies arrive fully assembled.
- Immutable – Can’t accidentally swap your database for a toaster mid-request.
- Testing-friendly – No Spring magic needed in unit tests.
Constructor Injection with Lombok
WIth Lombok, Constructor Injection is even simplified (and this is my recommended approach):
@RestController
@RequiredArgConstructor // <-- Lombok annotation
public class CheckoutController {
private final PaymentService paymentService;
//Controller logic
}
As a final note on this topic, I really recommend CodeAesthetic’s video “Dependency Injection, The Best Pattern”.