What is Inversion of Control (IoC), and how does Spring's container implement it?
Quick Answer
Inversion of Control means an object's dependencies are supplied to it from the outside, instead of the object creating or looking them up itself. This inverts the traditional flow where code controls its own dependency creation. Spring implements this via its IoC container (the ApplicationContext): it reads bean definitions (from annotations or XML), instantiates objects, wires their dependencies together, and manages their lifecycle. Application code just declares what it needs, and the container provides it.
Detailed Answer
In traditional procedural code, an object creates its own collaborators directly:
class OrderService {
private PaymentGateway gateway = new StripeGateway(); // OrderService controls its own dependency
}
Inversion of Control flips this around. The object just declares what it needs. Something external supplies it. Control over creating and wiring dependencies moves out of the object and into a container:
class OrderService {
private final PaymentGateway gateway;
OrderService(PaymentGateway gateway) { this.gateway = gateway; } // supplied from outside
}
Spring's IoC container (usually accessed via ApplicationContext) is what performs this inversion at runtime:
- It scans for bean definitions — via component scanning (
@Component,@Service, ...),@Beanmethods in@Configurationclasses, or (historically) XML. - It instantiates the beans. It resolves each one's declared dependencies (constructor parameters,
@Autowiredfields/setters) by looking them up among other managed beans. - It wires everything together and manages each bean's full lifecycle (initialization callbacks, scope, destruction).
@Service
class OrderService {
private final PaymentGateway gateway;
@Autowired // Spring resolves and injects this automatically
OrderService(PaymentGateway gateway) { this.gateway = gateway; }
}
The practical benefit: OrderService never mentions a concrete class like StripeGateway, only the PaymentGateway abstraction. The container decides which implementation to plug in. That's what makes it easy to swap implementations — for tests, different environments, or different providers — without touching OrderService itself.