1.1 Spring Framework & IoC Container
← Back to Chapter 1: Spring & Spring Boot Fundamentals
The core purpose of the Spring Framework is enterprise simplification through Inversion of Control (IoC) and Dependency Injection (DI). By managing component lifecycles, configuration, and dependencies within a dedicated container, Spring decouples domain logic from infrastructural wiring.
1. Inversion of Control (IoC) Principle
In traditional procedural or object-oriented programming without IoC, a consumer object directly controls the creation, configuration, and lifecycle of its collaborators via the new operator:
// Tightly coupled: OrderService dictates exactly how PaymentProcessor is created
public class OrderService {
private final PaymentProcessor paymentProcessor = new StripePaymentProcessor();
}
With Inversion of Control, this responsibility is inverted and handed over to an external runtime orchestrator (the Spring Container):
// Loosely coupled: OrderService declares its collaborator requirement, container injects it
@Service
public class OrderService {
private final PaymentProcessor paymentProcessor;
public OrderService(PaymentProcessor paymentProcessor) {
this.paymentProcessor = paymentProcessor;
}
}
IoC means the control of creating and managing objects is transferred from the application code to the Spring container.
Architectural Benefits:
- Testability: Dependencies can easily be mocked or stubbed during unit testing without launching full infrastructure.
- Maintainability: Implementations can be swapped via configuration without altering downstream consumers.
- Separation of Concerns: Business services concentrate purely on domain logic rather than object instantiation graphs.
2. BeanFactory vs ApplicationContext
Spring provides two central container interfaces for managing beans:
┌──────────────────────────────────────────────┐
│ BeanFactory (org.springframework.beans) │
│ - Lazy initialization by default │
│ - Lightweight memory footprint │
│ - Basic DI & lifecycle support │
└──────────────────────┬───────────────────────┘
│ inherits
┌──────────────────────▼───────────────────────┐
│ ApplicationContext (org.springframework.context)
│ - Eager initialization of singletons │
│ - Enterprise services (AOP, Events, i18n) │
│ - Environment, Profiles, & ResourceLoader │
└──────────────────────────────────────────────┘
| Feature | BeanFactory | ApplicationContext |
|---|---|---|
| Package | org.springframework.beans.factory | org.springframework.context |
| Bean Loading | Lazy (instantiates when getBean() called) | Eager (instantiates singletons on startup) |
| Annotation Support | Requires manual post-processors | Built-in (@Autowired, @PostConstruct) |
| Enterprise Services | Minimal | AOP, Internationalization, Events, Transactions |
| Primary Usage | Resource-constrained embedded devices | Modern Web & Enterprise Spring Boot apps |
BeanFactory
Basic container functionality:
Bean creation
Dependency injection
Bean management
ApplicationContext
Provides BeanFactory functionality plus:
Event handling
Internationalization
Application configuration
Resource loading
AOP integration
More enterprise features
3. Spring Container Lifecycle Stages
When the ApplicationContext bootstraps, it executes a rigorous lifecycle sequence:
- Resource Loading: Reads configuration sources (Java
@Configuration, XML, annotations). - Bean Definition Registration: Scans classpath and registers metadata (
BeanDefinition). - BeanFactoryPostProcessors: Runs customizations on bean metadata (e.g., resolving property placeholders).
- Bean Instantiation: Instantiates beans using constructors or factory methods.
- Dependency Injection: Populates properties and injects collaborating bean references.
- Aware Interfaces: Invokes
BeanNameAware,BeanFactoryAware,ApplicationContextAware. - BeanPostProcessor (Before Init): Executes
postProcessBeforeInitializationfor cross-cutting hooks. - Initialization: Invokes
@PostConstruct,InitializingBean.afterPropertiesSet(), or custominitMethod. - BeanPostProcessor (After Init): Executes
postProcessAfterInitialization(e.g., wrapping target beans in CGLIB/JDK dynamic proxies for AOP and@Transactional). - Ready for Use: Beans are served to satisfy application requests.
- Destruction (On Context Close): Invokes
@PreDestroy,DisposableBean.destroy(), or customdestroyMethod.