IoC Container
Understand the Spring IoC Container — the heart of Spring that manages object creation, dependency wiring, and bean lifecycle in every enterprise application.
Last reviewed: January 2025
🔍 What Is It?
The Spring IoC Container is the core runtime of the Spring Framework.
What it does:
- →Creates objects (beans) based on your configuration
- →Wires dependencies between beans (Dependency Injection)
- →Manages lifecycle — initializes, uses, and destroys beans
- →Provides beans to whoever requests them
Two container implementations:
- →
BeanFactory— basic container (lazy initialization, rarely used directly) - →
ApplicationContext— enhanced container with events, AOP, i18n, eager init (always use this)
ApplicationContext implementations:
- →
AnnotationConfigApplicationContext— Java config, no XML - →
ClassPathXmlApplicationContext— XML config (legacy) - →
WebApplicationContext— for web applications - →
SpringApplication.run()creates the right one automatically in Spring Boot
Bean definition sources:
- →
@Component,@Service,@Repository,@Controller— classpath scanning - →
@Beanmethods in@Configurationclasses - →Auto-configuration classes
🎯 Why Do We Need It?
Without IoC, you manually create and wire every object:
// Without Spring — tight coupling, untestable
UserRepository repo = new JpaUserRepository(dataSource);
EmailService email = new SmtpEmailService(smtpConfig);
PasswordEncoder encoder = new BCryptPasswordEncoder(12);
UserService service = new UserServiceImpl(repo, email, encoder);
UserController controller = new UserController(service);
// If UserService changes constructor, every caller must changeWith IoC:
@Service
public class UserServiceImpl implements UserService {
// Spring injects these — you don't create them
public UserServiceImpl(UserRepository repo, EmailService email, PasswordEncoder encoder) { ... }
}
// Spring handles the wiring graph automaticallyBenefits:
- →Loose coupling — components don't create their dependencies
- →Testability — inject mock dependencies in unit tests
- →Centralized config — change implementations without changing consumers
- →Lifecycle management — Spring handles initialization and cleanup
🏗️ What Happens in Real Projects?
IoC is invisible but everywhere in a Spring Boot app:
- →Your
@Servicedoesn't create its@Repository— Spring injects it - →Your
@Controllerdoesn't create its@Service— Spring injects it - →
DataSource,EntityManagerFactory,TransactionManager— Spring creates from your config - →
KafkaTemplate,RestTemplate,RedisTemplate— Spring creates and injects
In a microservice with 50 classes, Spring manages all 50 objects and their dependencies automatically.
⚙️ How It Works
Container startup:
- Scan classpath for
@Component,@Service,@Repository,@Controller - Process
@Configurationclasses and@Beanmethods - Build a dependency graph of all beans
- Create beans in dependency order (dependencies first)
- Inject dependencies (constructor, setter, or field)
- Call
@PostConstructmethods - Application is ready
On shutdown:
- Call
@PreDestroymethods - Close resources (DB connections, thread pools)
- JVM exits
Bean naming:
- →Default: camelCase class name (
UserServiceImpl→userServiceImpl) - →Custom:
@Service("userService")or@Bean("myBean")
💻 Example
IoC Container in Practice — How Spring creates and wires beans in a real application.
🤔 Common Confusions
❓ What is the difference between BeanFactory and ApplicationContext?
BeanFactory is the basic container with lazy initialization. ApplicationContext extends it with eager initialization, event publishing, AOP support, i18n, and more. Always use ApplicationContext (which SpringApplication.run() creates automatically). BeanFactory is only relevant for extremely memory-constrained environments.
❓ Can Spring manage objects I create with "new"?
No. Objects created with "new" are not Spring beans — Spring doesn't know about them and won't inject dependencies into them. This is a common mistake: if you do "new UserService()" inside a @Controller, the UserService's dependencies won't be injected. Always let Spring create your beans.
❓ What is the difference between @Component, @Service, @Repository, and @Controller?
@Service, @Repository, and @Controller are all specializations of @Component — they all register a bean in the container. The difference is semantic and functional: @Repository enables JPA exception translation, @Controller marks it as a web handler, @Service has no extra behavior but documents intent. Use the right one for each layer.
🚨 Common Production Issues
Circular dependency: BeanA depends on BeanB which depends on BeanA — refactor to break the cycle, or use @Lazy on one injection point
Bean not found (NoSuchBeanDefinitionException) — class not in component scan path or missing @Component annotation
Multiple beans of same type (NoUniqueBeanDefinitionException) — use @Primary or @Qualifier to disambiguate
ApplicationContext startup failure due to bean initialization error — check @PostConstruct methods for exceptions
Prototype-scoped bean injected into singleton — use ObjectProvider<T> or @Lookup to get a new instance each time
✅ Best Practices
Always use constructor injection — it makes dependencies explicit and enables final fields
Keep @Configuration classes focused — one config class per concern (DataSourceConfig, SecurityConfig)
Use @PostConstruct for initialization logic, not constructors (dependencies are available)
Avoid circular dependencies by redesigning — they indicate architectural issues
Use @Lazy sparingly — it hides startup problems until first use
🏛️ Architect's Note
The IoC container is the reason Spring applications are so testable. Because all dependencies are injected, you can substitute any bean with a mock in tests. This is why Spring applications typically have 80%+ test coverage — the architecture makes testing natural. When you see code that's hard to test in a Spring app, it's almost always because something is being created with new instead of being injected.
💬 Frequently Asked Questions
🎯 Key Takeaways
🔗 Related Topics
🎯 Practice this topic in interviews
↗ Where this topic fits
Spring Boot Technology Guide
Return to the Spring Boot learning hub.
Backend Engineer Career Path
A structured journey through Core Java, Spring Boot, production backend engineering, and interview preparation.
Full Stack Java Developer Career Path
A guided route through frontend foundations, Java backend engineering, delivery workflows, and interview readiness.
Sources
Sources / References
Use these Spring Boot references to verify the concept in official docs and continue into the most relevant SplashRide pages.
Official documentation
Related SplashRide pages
SplashRide Spring Boot learning path
Browse the full Spring Boot topic collection and learning order on SplashRide.
Spring Boot Interview Prep
Practice Spring Boot interview questions and scenario-based answers.
Backend Engineer Career Path
A structured journey through Core Java, Spring Boot, production backend engineering, and interview preparation.
Full Stack Java Developer Career Path
A guided route through frontend foundations, Java backend engineering, delivery workflows, and interview readiness.
Dependency Injection
Master Spring's three DI styles — constructor, setter, and field injection — and understand why constructor injection is the only correct choice for production code.
Bean Lifecycle
Understand the complete Spring bean lifecycle — from instantiation through initialization to destruction — and how to hook into each phase for initialization and cleanup.