Episode 2 | Spring Core | Understanding IoC, Dependency Injection & Beans In Episode 1, I covered the WHY behind Spring — tight coupling, and how Spring takes over creating and providing objects (IoC + DI) instead of classes creating their own dependencies.
This episode picks up from there with the parts I hadn't covered yet: how Spring actually does that under the hood — Beans, the Spring Container, and Component Scanning. 🔑 Keywords → 🧠 Understand → 💡 Why? → 💻 Practice → 🎯 Interview Questions → 🛠️ Project 🔑 Keywords for This Episode IoC & Dependency Injection (quick recap) Spring Bean Spring Container / ApplicationContext Component Scanning 1️⃣ Quick Recap: IoC & Dependency Injection From Episode 1: instead of a class creating its own dependency — — Spring creates the dependency and hands it to the class.
That's Inversion of Control (IoC).
In code, this usually looks like a constructor parameter: no longer says "let me create a TicketRepository." It says "I need a TicketRepository" — and Spring supplies one.
That act of supplying it is Dependency Injection (DI).
IoC = who's in control of creating/managing objects → Spring.
DI = how a class actually receives what it needs → passed in, not self-created.
That's the recap.
Now — where do these objects Spring creates actually come from, and where do they live? 2️⃣ Spring Bean — what Spring actually manages When Spring creates and manages an object for you, that object is called a Bean.
This is the vocabulary you'll see everywhere in Spring code and docs, so it's worth being precise about it.
The annotation is a signal to Spring: "this class should be managed by you." When Spring creates an object from this class, that specific object — the one Spring created and is tracking — is a Bean.
Compare that to doing it yourself: This object is a completely ordinary Java object.
Spring has no idea it exists.
It's not a Bean — Spring can't inject it anywhere, manage its lifecycle, or wire its dependencies, because Spring never created it and doesn't know about it.
So the distinguishing line is simple: A Spring Bean isn't a special kind of class — it's an object that Spring itself created and is managing.
The exact same class can produce a Bean (if Spring creates it) or a plain object (if you create it with ).
This matters because dependency injection only works on Beans.
If isn't a Bean, Spring has nothing to inject into . 3️⃣ Spring Container (a.k.a.
ApplicationContext) So Beans need to be created and tracked somewhere.
That "somewhere" is the Spring Container — in practice, you'll most often see it called the ApplicationContext, which is Spring's concrete implementation of the container.
Concretely, the Container is responsible for: Creating Bean instances (calling the constructor, essentially) Storing references to every Bean it creates, so it can find them again Figuring out each Bean's dependencies — e.g. it sees needs a Injecting those dependencies — passing the right Bean into the right constructor Managing the Bean's lifecycle — when it's created, and when it's cleaned up when the app shuts down Here's the flow when your app starts: You never call yourself — the Container does this wiring for the entire application, for every Bean, automatically.
Spring Container / ApplicationContext = the running system inside your app that creates every Bean, keeps track of them, and wires their dependencies together. 4️⃣ Component Scanning — how the Container finds classes to manage This raises an obvious question: the Container can't manage a class it doesn't know exists.
So how does it discover in the first place?
That's Component Scanning.
When your Spring app starts, Spring scans your project's packages looking for classes marked with specific annotations: These are all technically variations of — Spring treats them the same way for scanning purposes, they just also carry extra meaning (e.g. also tells Spring to translate database exceptions).
Concretely, the process looks like this: