Inversion of Control & the Container
The idea at Spring's core: hand control of object creation to a container, and let it wire your application together.
On this page
Every application is a graph of objects that depend on each other: a controller needs a service, the service needs a repository, the repository needs a data source. The question is - who creates and connects all those objects?
In plain Java, you do, by hand, with new:
DataSource dataSource = new HikariDataSource(config);
BookRepository repository = new BookRepository(dataSource);
BookService service = new BookService(repository);
BookController controller = new BookController(service);That's tedious, but the real pain is deeper: every object is now hard-wired to a
specific implementation. Swap BookRepository for a caching version and you're
editing construction code everywhere. Your objects are tangled together at the
seams.
Inversion of Control
Inversion of Control (IoC) flips this around. Instead of each object creating and locating its own dependencies, it simply declares what it needs, and a central authority - the container - creates the objects and hands each one its dependencies.
Picture a theatre. In the tangled version, each actor fetches their own props, finds their own costume, and cues themselves - chaos. In a real production, a stage manager hands every performer exactly the props they need, exactly when they need them. The actors just act. Spring's container is that stage manager: you say what you need, it supplies it. Control over "who gets what" is inverted away from your objects and into the container.
The container
The container is Spring's core. You describe your objects (we'll see how in the next lessons), and the container:
- Instantiates them,
- Wires their dependencies together, and
- Manages them for the app's lifetime.
The objects it manages are called BeanAny object the Spring container instantiates, wires, and manages.s. The container itself is
represented by the ApplicationContext:
// Spring reads your configuration and builds the whole object graph for you
ApplicationContext context =
new AnnotationConfigApplicationContext(AppConfig.class);
// Ask the container for a fully-wired object - no `new`, no manual wiring
BookService service = context.getBean(BookService.class);
service.findAll();You never called new BookRepository(...) or new BookService(...). You declared
the pieces; the container assembled the graph. In a Spring Boot app you rarely even
call getBean - the framework wires everything and just runs your code.
Nothing exists yet — you've only written the classes and their dependencies.
Why this matters
Because the container owns construction, it can do things for every object it manages, without you writing a line:
- Swap implementations by changing configuration, not code.
- Share single instances (the default) so one repository serves the whole app.
- Wrap objects transparently to add transactions, security, caching, and metrics (you'll see how in the AOP lesson).
That last point is the quiet superpower: since Spring hands out the objects, it can hand out enhanced objects. This is the foundation the entire ecosystem is built on.
You describe the 'what', Spring decides the 'how'
IoC is a form of declarative programming. You declare the components and their needs; the container works out instantiation order, resolves dependencies, and manages lifecycles. Less wiring code, fewer wiring bugs.
In the hand-wired snippet at the top, suppose you want BookService to use a new
CachingBookRepository instead of BookRepository. In the manual approach, what
has to change - and who has to know about the swap? Now describe how the IoC
approach makes the same swap a configuration change.
In Inversion of Control, who is responsible for creating an object's dependencies?
Key takeaways
- Inversion of Control means objects declare their dependencies instead of creating or locating them; a container supplies them.
- The Spring container (ApplicationContext) instantiates, wires, and manages your objects - called beans - for the app's lifetime.
- Because the container owns construction, it can swap implementations via config, share single instances, and transparently add cross-cutting behavior.
- This container is the engine the entire Spring ecosystem is built on.