Module 17: Spring Boot Service Development
IoC and Dependency Injection
Understand Spring inversion of control as a design aid, not just a framework rule. You will learn how the container creates objects, wires dependencies, and improves testability when you keep construction explicit and responsibilities small.
Author
Java Learner Editorial Team
Reviewer
Technical review by Java Learner
Last reviewed
2026-04-17
Java version
Java 25 LTS
Learning goals
- Explain what the IoC container is responsible for and what your code still owns
- Prefer constructor injection because it keeps dependencies visible and testable
- See dependency injection as a design tool for decoupling, not only as annotation syntax
Before you start
- You understand classes, interfaces, and object collaboration
Lesson roadmap: Start with the mental model, then follow the design choices, common pitfalls, and the practical workflow you should apply in a real project.
Inversion of control means your code stops manually wiring every dependency itself: The framework constructs and connects components based on configuration and annotations.
Dependency injection is the most visible result of that model: A service receives what it needs instead of creating those dependencies internally.
Constructor injection is the best default: It makes dependencies explicit and supports immutability and testing.
Design benefit: Components become easier to reason about because their collaborators are declared up front.
Mental model: Without IoC, your classes often create their own collaborators directly. With IoC, the application container assembles the object graph so each class can focus on its own behavior.
Constructor injection is a readability win: It makes required dependencies obvious, supports immutable fields, and makes unit testing easier because collaborators can be supplied directly.
What the container should not hide: Framework wiring should not become an excuse for unclear architecture. Even with Spring, teams still need sensible package structure, small services, and explicit boundaries.
Bean scope awareness: Most services are singleton beans, which means they should be stateless or at least very careful about shared mutable state.
How to study this module: Keep one small service running while you learn. Seeing one controller call one service and one repository is much easier than reading isolated annotations with no end-to-end flow.
Code review mindset: Spring code stays healthy when each layer has one job. Controllers translate HTTP, services coordinate rules, repositories load and save data, and configuration wires the environment together.
Production habit: Favor explicit boundaries over framework magic. Auto-configuration is helpful, but teams still need to know where behavior comes from and how to override it safely.
Runnable examples
Constructor injection keeps dependencies explicit
@Service
class OrderService {
private final PaymentGateway paymentGateway;
OrderService(PaymentGateway paymentGateway) {
this.paymentGateway = paymentGateway;
}
}Expected output
The service declares its dependency instead of creating it internally.
A service receives its collaborator through the constructor
@Service
class ReportService {
private final UserRepository userRepository;
ReportService(UserRepository userRepository) {
this.userRepository = userRepository;
}
}Expected output
The dependency is explicit, required, and easy to replace in a test.
Common mistakes
Using field injection because it looks shorter
Constructor injection makes dependencies clearer and keeps tests simpler.
Packing too many unrelated responsibilities into one service bean
IoC helps wiring; it does not replace good class design.
Mini exercise
Refactor a hypothetical service that creates its own repository with `new` so the repository is injected through the constructor instead. Then explain in one sentence why the new version is easier to test.
Summary
- IoC means the framework helps wire components together.
- Dependency injection keeps dependencies explicit.
- Constructor injection is the clearest and safest default.
- IoC is easiest to understand when you see it as object-graph assembly.
- Constructor injection makes application structure visible instead of hidden.
Next step
Now see how Spring Boot reduces setup work with starters and auto-configuration.
Sources used