Spring Boot Dependency Injection
Dependency Injection (DI) is the technique Spring Boot uses to connect the different pieces of your app together automatically. Instead of creating objects manually, you ask Spring to provide them.
The Problem Without DI
Without DI — you create every object yourself:
public class OrderController {
private OrderService service = new OrderService(); // Hardcoded
// ↑ You create it manually
// ↑ Hard to test, hard to swap
}
When your app grows, tracking and managing these object creations becomes a full-time job.
The Coffee Shop Analogy
You walk into a coffee shop and say "I need a latte." The barista (Spring) makes the latte and hands it to you. You do not grind beans, heat milk, or own an espresso machine. You just receive what you asked for. DI works the same way — Spring creates the objects your class needs and delivers them.
How DI Works in Spring Boot
Spring Container (IoC Container)
┌────────────────────────────────────────┐
│ │
│ Creates: OrderService │
│ Creates: OrderRepository │
│ Creates: OrderController │
│ │
│ Wires together automatically │
│ │
└────────────────────────────────────────┘
│
▼ injects
┌───────────────┐ ┌──────────────┐
│OrderController│ ────▶│ OrderService │
└───────────────┘ └──────┬───────┘
│
▼
┌──────────────────┐
│ OrderRepository │
└──────────────────┘
Constructor Injection (Recommended)
Pass dependencies through the constructor. This is the cleanest and most testable approach.
@RestController
public class OrderController {
private final OrderService orderService;
public OrderController(OrderService orderService) { ← Spring injects here
this.orderService = orderService;
}
@GetMapping("/orders")
public List<Order> getOrders() {
return orderService.findAll();
}
}
Spring sees that OrderController needs an OrderService and automatically provides one.
@Autowired Annotation
When a class has only one constructor, Spring injects automatically. For field injection, use @Autowired — though constructor injection is preferred:
@Service
public class OrderService {
@Autowired ← Spring injects this
private OrderRepository repository;
public List<Order> findAll() {
return repository.findAll();
}
}
Three Types of Injection Compared
Type How It Looks Recommended? ───────────── ───────────────────── ──────────── Constructor OrderService(Repo r) YES ✓ Setter setRepo(Repo r) Sometimes Field (@Autowired) @Autowired Repo r Avoid in production
Constructor injection is recommended because it makes dependencies explicit, allows immutable fields (final), and makes unit testing straightforward.
The IoC Container
IoC stands for Inversion of Control. In traditional programming, your code controls when objects get created. With IoC, you hand that control over to Spring.
Traditional: Your code → creates → objects → uses them IoC: Spring → creates → objects → injects → your code uses them
The Spring IoC container is the engine behind DI. It holds all your beans, resolves their dependencies, and hands them out when needed.
What Happens at Startup
App starts
│
▼
Spring scans all classes with @Component, @Service,
@Repository, @Controller, @RestController
│
▼
Creates instances (beans) for each
│
▼
Checks each bean's constructor — what does it need?
│
▼
Injects matching beans
│
▼
App is ready to handle requests
Summary
- DI means Spring creates and provides objects your class needs
- Constructor injection is the recommended approach
- The IoC Container manages all bean creation and wiring
@Autowiredtells Spring where to inject a dependency- DI makes code easier to test because you can swap real objects with mock ones
