Inversion of Control (IoC) is a fundamental principle of the Spring Framework that shifts responsibility for object creation and dependency management from application code to the Spring container. Instead of your code instantiating and wiring its own dependencies, Spring’s IoC container does it for you, leading to looser coupling and more testable, maintainable code.
1. Core Concepts
Term | Description |
---|---|
IoC | “Inverting” the flow of control—your code delegates control of object creation to a container rather than calling new itself. |
DI (Dependency Injection) | A common technique for implementing IoC: the container “injects” required dependencies into your objects. |
Bean | Any object that Spring manages in its container. |
BeanFactory | The basic, low-level IoC container interface that provides bean instantiation and lifecycle. |
ApplicationContext | A richer IoC container (supersets BeanFactory) that adds support for internationalization, event propagation, AOP integration, and more. |
2. Types of Dependency Injection
- Constructor Injection
- Dependencies are provided as constructor arguments.
- Enables immutable objects and makes required dependencies explicit.
@Component
public class UserService {
private final UserRepository repo;
@Autowired
public UserService(UserRepository repo) {
this.repo = repo;
}
}
- Setter Injection
- Dependencies are set via JavaBean setter methods.
- Allows optional dependencies and re-injection.
@Component
public class EmailService {
private MailClient client;
@Autowired
public void setMailClient(MailClient client) {
this.client = client;
}
}
- Field Injection (not generally recommended)
- Dependencies are injected directly into fields.
@Component
public class OrderService {
@Autowired
private PaymentProcessor processor;
}
3. How Spring’s IoC Container Works
- Configuration
-
Java-based (
@Configuration
+@Bean
methods) -
Annotation-based (
@Component
,@Service
,@Repository
, etc., combined with@ComponentScan
) - XML (legacy)
- Component Scanning & Bean Definitions
- Spring scans specified packages for annotated classes, registers them as bean definitions.
- Dependency Resolution
- When the container starts, it reads bean definitions, resolves dependencies by type (and qualifier, if needed), and injects them.
- Bean Lifecycle
-
Instantiation → Populate properties/injections →
@PostConstruct
/ init-method → use →@PreDestroy
/ destroy-method
4. Bean Scopes
Scope | Description |
---|---|
singleton | (Default) One shared instance per Spring container. |
prototype | A new instance each time it’s requested from the container. |
request | One instance per HTTP request (web applications). |
session | One instance per HTTP session (web applications). |
application | One instance per ServletContext (web applications). |
@Component
@Scope("prototype")
public class ShoppingCart { … }
5. Putting It All Together: Minimal Example
@Configuration
@ComponentScan("com.example.app")
public class AppConfig { }
@Service
public class GreetingService {
public String greet() { return "Hello, IoC!"; }
}
@Component
public class Runner {
private final GreetingService svc;
@Autowired
public Runner(GreetingService svc) { this.svc = svc; }
public void run() { System.out.println(svc.greet()); }
}
public class Main {
public static void main(String[] args) {
AnnotationConfigApplicationContext ctx =
new AnnotationConfigApplicationContext(AppConfig.class);
Runner runner = ctx.getBean(Runner.class);
runner.run(); // prints “Hello, IoC!”
ctx.close();
}
}
-
AnnotationConfigApplicationContext
creates the IoC container. - It scans for
@Service
and@Component
, builds beans. - It injects
GreetingService
intoRunner
’s constructor. - Your application code simply retrieves and uses beans—no
new
calls!
✨ Benefits of IoC in Spring
- Loose Coupling: Beans depend on interfaces, not concrete implementations.
- Testability: Swap real implementations with mocks easily.
- Configurability: Change wiring via configuration, not code.
- Maintainability: Centralized control of object lifecycles and dependencies.
Let me know if you’d like a deeper dive—e.g., custom injection annotations, conditional beans, or advanced lifecycle hooks!
Top comments (0)