Chaturmind
LearnDSASystem DesignDevOpsEngineering GrowthBlog
Start learning
Chaturmind

Structured learning paths for engineers who want to go deep. Written by practitioners.

Learn

  • Java
  • DSA
  • System Design
  • Spring Boot
  • AI / ML
  • DevOps
  • Engineering Growth

Company

  • Blog
  • Contact

Legal

  • Privacy Policy
  • Terms of Service

© 2026 Chaturmind. All rights reserved.

Built for engineers who want to go deep.


← Spring Boot REST API Development

Spring Boot Basics

  • What is Spring Boot?
  • Dependency Injection
  • Building REST Controllers

Validation & Error Handling

  • Bean Validation with @Valid
  • Global Exception Handling

Spring Framework Internals

  • IoC Container Fundamentals
  • Bean Lifecycle In Detail
  • Component Scanning & Configuration
  • Auto-Configuration Mechanism
  • Spring AOP
  • @Transactional Deep Dive

Microservices Architecture

  • Monolith to Microservices Decomposition
  • API Gateway
  • Service Discovery
  • Inter-Service Communication Choices
  • Event-Driven Architecture Patterns
  • Messaging Technology Choices

Resilience Patterns

  • Configuration Management
  • Circuit Breaker Pattern
  • Retry & Backoff Strategies
  • Bulkhead & Rate Limiting
  • Timeout Strategy
  • Why Microservices Fail

Distributed Data & Consistency Patterns

  • Two-Phase Commit
  • Saga Pattern
  • Outbox Pattern
  • Eventual Consistency Design
  • CQRS Basics
  • CAP Theorem

Observability & Operations

  • Centralized Logging
  • Distributed Tracing
  • Metrics & Monitoring
  • Alerting Strategy
  • Health Checks

Payment Systems

  • Payment — Requirements
  • Payment — Core Flow
  • Payment — Idempotency Implementation
  • Payment — Failure Handling & Reconciliation
  • Payment — Security

Order Management System

  • OMS — Requirements
  • OMS — State Machine Design
Chaturmind
← Spring Boot REST API Development

Spring Boot Basics

  • What is Spring Boot?
  • Dependency Injection
  • Building REST Controllers

Validation & Error Handling

  • Bean Validation with @Valid
  • Global Exception Handling

Spring Framework Internals

  • IoC Container Fundamentals
  • Bean Lifecycle In Detail
  • Component Scanning & Configuration
  • Auto-Configuration Mechanism
  • Spring AOP
  • @Transactional Deep Dive

Microservices Architecture

  • Monolith to Microservices Decomposition
  • API Gateway
  • Service Discovery
  • Inter-Service Communication Choices
  • Event-Driven Architecture Patterns
  • Messaging Technology Choices

Resilience Patterns

  • Configuration Management
  • Circuit Breaker Pattern
  • Retry & Backoff Strategies
  • Bulkhead & Rate Limiting
  • Timeout Strategy
  • Why Microservices Fail

Distributed Data & Consistency Patterns

  • Two-Phase Commit
  • Saga Pattern
  • Outbox Pattern
  • Eventual Consistency Design
  • CQRS Basics
  • CAP Theorem

Observability & Operations

  • Centralized Logging
  • Distributed Tracing
  • Metrics & Monitoring
  • Alerting Strategy
  • Health Checks

Payment Systems

  • Payment — Requirements
  • Payment — Core Flow
  • Payment — Idempotency Implementation
  • Payment — Failure Handling & Reconciliation
  • Payment — Security

Order Management System

  • OMS — Requirements
  • OMS — State Machine Design
HomeLearnSpring BootSpring Boot REST API DevelopmentSpring Framework Internals
✓ FreeIntermediate· 9 min read

IoC Container Fundamentals

Inversion of Control as the principle underneath Dependency Injection, BeanFactory vs ApplicationContext, the five bean scopes, and what happens when Spring finds two candidate beans and no way to pick.

Published September 23, 2026


IoC Container Fundamentals

Dependency Injection (see the existing Dependency Injection lesson) is the mechanism. Inversion of Control is the principle behind it, and this lesson covers the container that actually implements it.

Inversion of Control: who's in charge of wiring

In a non-IoC design, a class controls its own dependencies — it calls new on whatever it needs, deciding both what it depends on and when that dependency gets created. IoC inverts this: the framework creates objects and wires their dependencies together, and your classes just declare what they need (typically via a constructor) without ever calling new on their own collaborators. The "inversion" is specifically about who controls object creation and wiring — it moves from your code to the container.

BeanFactory vs ApplicationContext

Both are Spring's IoC container interfaces, but with a meaningful difference in initialization strategy and scope:

  • BeanFactory — the more basic container. Beans are created lazily, only when first requested — minimal footprint, minimal startup cost.
  • ApplicationContext — extends BeanFactory with enterprise features (event publishing, internationalization, AOP integration, easier configuration) and, critically, eagerly initializes all singleton beans at startup by default. This eager initialization is deliberate: it means configuration errors (a missing dependency, a bean that fails to construct) surface immediately at application startup rather than lazily, at some unpredictable point during request handling in production. ApplicationContext is what every real Spring Boot application actually uses — BeanFactory is mostly of historical/academic interest at this point.

Bean scopes

ScopeLifetime
singleton (default)One instance per Spring container, shared everywhere it's injected
prototypeA new instance every time the bean is requested/injected
requestOne instance per HTTP request (web-aware contexts only)
sessionOne instance per HTTP session (web-aware contexts only)
applicationOne instance per ServletContext (effectively singleton, but scoped to the web application, not just the Spring container)

The default (singleton) is almost always correct for stateless services, repositories, and controllers — reach for prototype specifically when a bean holds genuinely per-use mutable state that must not be shared across concurrent users (rare in typical REST backends, more common in batch/worker contexts).

Bean definition sources

Three ways to tell Spring "this is a bean": XML configuration (legacy, rarely used in new code), annotations (@Component/@Service/@Repository/@Controller, covered fully in Component Scanning & Configuration), and Java config (@Configuration classes with @Bean methods, also covered there). Modern Spring Boot applications lean almost entirely on annotations plus Java config; XML persists mainly in legacy codebases being incrementally modernized.

ApplicationContext hierarchy: parent-child contexts

A Spring web application can have a root context (shared, application-wide beans — services, repositories) and a child web context (web-layer-specific beans — controllers, view resolvers) that can see everything in the parent but not vice versa. This isn't relevant to most simple Spring Boot REST APIs (which typically run a single flat context), but matters in larger applications composing multiple modules, or in traditional Spring MVC setups predating Spring Boot's simplified single-context model.

Dependency injection types

  • Constructor injection (preferred) — dependencies passed via the constructor, can be final, impossible to construct the object in an invalid (partially-wired) state.
  • Setter injection — dependencies set via setter methods after construction — allows optional dependencies and reconfiguration after construction, at the cost of a window where the object exists but isn't fully wired yet.
  • Field injection (@Autowired directly on a field) — the most concise to write, but hides the dependency list, prevents final fields, and makes the class harder to unit test without a DI framework (see Dependency Inversion's own comparison of these three).

When Spring can't decide: NoUniqueBeanDefinitionException

@Component class EmailNotifier implements Notifier { ... }
@Component class SmsNotifier implements Notifier { ... }

@Service
class AlertService {
    AlertService(Notifier notifier) { ... } // which Notifier? Spring has two candidates and no tiebreaker
}

With two beans of the exact same type and no @Qualifier or @Primary to disambiguate (see Component Scanning & Configuration), Spring throws NoUniqueBeanDefinitionException at startup — not a guess, not a silent pick of "whichever was registered first." This fail-fast behavior is a direct consequence of ApplicationContext's eager singleton initialization: the ambiguity is caught immediately, before the application ever serves a single request.

Follow-up questions this topic invites — and their answers

Q: If ApplicationContext eagerly creates every singleton, does that mean startup time scales with bean count? A: Yes, meaningfully — this is one practical reason large Spring Boot applications can have startup times in the seconds, and it's part of what Auto-Configuration Mechanism's conditional-bean-creation machinery is designed to minimize: only create the beans a given deployment actually needs, based on what's on the classpath and configured.

Q: Can a bean be both a singleton in the Spring container sense and still have per-request state? A: Only if that state is stored somewhere request-scoped rather than in the bean's own instance fields — e.g. reading from SecurityContextHolder's thread-local storage (see Authentication Mechanics) rather than storing the current user directly as a field on a singleton service, which would leak across concurrent requests exactly like the ThreadLocal leak pattern in Memory Leaks in Java.

Q: Why would you ever choose prototype scope over just calling new directly and skipping the container entirely? A: A prototype-scoped bean still gets full dependency injection from the container on every creation — new directly would mean manually wiring every dependency yourself. Prototype scope gets you "a fresh instance every time" while keeping all of DI's benefits, which plain new inside application code would sacrifice entirely.

Q: How does ApplicationContext's eager startup interact with a bean whose constructor makes a slow network call? A: It makes that slow call part of application startup time, not the first request's latency — a real tradeoff: slower deploys/restarts in exchange for a service that's either fully ready or fails fast at startup, rather than one that appears healthy but fails unpredictably on some later request depending on which bean happens to be lazily created first.

Previous

Global Exception Handling

Next

Bean Lifecycle In Detail

AI Tutor

Lesson: IoC Container Fundamentals

Quick actions

AI responses can be inaccurate. Verify critical information.