π Spring Core: Beans and the IoC Container
The Magic Factory Story
Imagine you own a toy factory. Instead of building every toy yourself, you have a magical factory manager who:
- Knows how to build every toy
- Keeps toys organized in special boxes
- Gives you the exact toy you need, when you need it
This magical factory manager is the IoC Container in Spring! Letβs explore how it works.
π― What is the IoC Container?
IoC = Inversion of Control
Think of it this way:
- Without IoC: YOU go to the store, find ingredients, cook your meal
- With IoC: A CHEF brings you the meal ready to eat
// Without IoC - You do everything
Car car = new Car();
Engine engine = new Engine();
car.setEngine(engine); // You connect things
// With IoC - Spring does it for you
@Autowired
Car car; // Spring gives you a ready car!
The IoC Container takes control of creating and connecting objects. You just ask, it delivers!
πͺ BeanFactory vs ApplicationContext
Spring has TWO types of factory managers:
BeanFactory - The Basic Manager
π¦ BeanFactory
βββ Creates beans when asked
βββ Uses less memory
βββ Basic features only
Like a small corner shop - has what you need, but minimal services.
ApplicationContext - The Super Manager
π¬ ApplicationContext
βββ Everything BeanFactory has
βββ Auto-detects beans
βββ Handles events
βββ Supports internationalization
βββ Integrates with web apps
Like a supermarket - more features, more convenient!
graph TD A[BeanFactory] -->|Basic| B[Creates Beans] C[ApplicationContext] -->|Extends| A C -->|Extra| D[Events] C -->|Extra| E[i18n Support] C -->|Extra| F[Web Integration] style C fill:#4CAF50,color:white style A fill:#2196F3,color:white
When to Use What?
| Scenario | Choose |
|---|---|
| Memory-constrained | BeanFactory |
| Normal apps | ApplicationContext |
| Web apps | ApplicationContext |
| Need events | ApplicationContext |
Simple Rule: Always use ApplicationContext unless you have a specific reason not to!
π§± What is a Bean?
A Bean is simply an object that Spring manages.
Real Life Example:
- Your toys at home = regular objects (you manage them)
- Toys in the factory warehouse = beans (factory manages them)
// This is a regular class
public class MusicPlayer {
public void play() {
System.out.println("Playing music!");
}
}
// Tell Spring "Hey, manage this for me!"
@Component
public class MusicPlayer {
public void play() {
System.out.println("Playing music!");
}
}
The @Component annotation is like putting a βHandle With Careβ sticker. Spring sees it and says: βIβll take care of this one!β
Bean Definition - The Recipe
A bean definition is the recipe Spring uses to create beans:
@Component
public class EmailService {
private String smtpServer = "mail.example.com";
public void sendEmail(String to) {
// send email logic
}
}
The recipe includes:
- Class name - what to create
- Scope - how many to create
- Dependencies - what it needs
- Properties - its settings
π Bean Lifecycle - From Birth to Goodbye
Every bean goes through a life journey:
graph TD A[π₯ Instantiation] --> B[π¦ Populate Properties] B --> C[π·οΈ Set Bean Name] C --> D[π Set Factory Reference] D --> E[βοΈ Post Process Before] E --> F[π Initialize] F --> G[βοΈ Post Process After] G --> H[β Ready to Use!] H --> I[π€ Destroy] style A fill:#E3F2FD style H fill:#C8E6C9 style I fill:#FFCDD2
The Story of Beanβs Life
1. Birth (Instantiation)
// Spring calls: new MusicPlayer()
2. Getting Dressed (Populate Properties)
@Autowired
private SpeakerService speaker;
// Spring connects the speaker
3. Learning Its Name (Aware Interfaces)
public class MyBean implements BeanNameAware {
public void setBeanName(String name) {
// "Hi, I'm MyBean!"
}
}
4. Growing Up (Initialization)
@PostConstruct
public void init() {
System.out.println("I'm ready to work!");
}
5. Working Hard (In Use)
musicPlayer.play(); // Bean doing its job
6. Retirement (Destruction)
@PreDestroy
public void cleanup() {
System.out.println("Goodbye, cleaning up!");
}
π¦ Bean Scopes - How Many Copies?
Scope decides how many copies of a bean exist.
Singleton (Default) - One for All
π Singleton Scope
Everyone gets the SAME toy
Request 1 β πΈ Guitar #1
Request 2 β πΈ Guitar #1 (same one!)
Request 3 β πΈ Guitar #1 (still same!)
@Component
@Scope("singleton") // optional, it's default
public class ConfigService {
// Only ONE instance ever!
}
Prototype - Fresh Copy Each Time
π¨ Prototype Scope
Everyone gets a NEW toy
Request 1 β πΈ Guitar #1
Request 2 β πΈ Guitar #2 (new one!)
Request 3 β πΈ Guitar #3 (another new!)
@Component
@Scope("prototype")
public class ShoppingCart {
// Each user gets their own cart!
}
Web Scopes (For Web Apps)
| Scope | Meaning | Example |
|---|---|---|
request |
New bean per HTTP request | Form data |
session |
New bean per user session | User profile |
application |
One per web app | Site settings |
@Component
@Scope("session")
public class UserPreferences {
private String theme = "dark";
}
π Singleton Thread Safety
Warning! Singleton doesnβt mean thread-safe!
The Problem
π€ User A βββββββ
ββββ π Same Singleton ββββ€
π€ User B βββββββ β
β
π₯ CONFLICT!
If two users change the same data at once, things break!
Bad Example - Not Thread Safe
@Component
public class Counter {
private int count = 0; // DANGER!
public void increment() {
count++; // Two threads = trouble!
}
}
Good Example - Thread Safe Solutions
Solution 1: No Shared State
@Component
public class Calculator {
// No instance variables
public int add(int a, int b) {
return a + b; // Safe!
}
}
Solution 2: Use Synchronized
@Component
public class Counter {
private int count = 0;
public synchronized void increment() {
count++; // Only one at a time
}
}
Solution 3: Use AtomicInteger
@Component
public class Counter {
private AtomicInteger count =
new AtomicInteger(0);
public void increment() {
count.incrementAndGet(); // Safe!
}
}
Golden Rule
π Keep singletons stateless (no changing data) or make them thread-safe!
π΄ Lazy Initialization - Wake Up Later!
By default, Spring creates all singletons at startup. But sometimes thatβs wasteful!
Eager (Default) - Create Now!
π App Starts
β
π¦ Create Bean A
π¦ Create Bean B
π¦ Create Bean C
β
β
Ready (even if we never use Bean C)
Lazy - Create When Needed
π App Starts
β
β
Ready (no beans created yet!)
β
π Someone needs Bean A
β
π¦ Create Bean A (just in time!)
@Component
@Lazy
public class ExpensiveService {
public ExpensiveService() {
// Takes 10 seconds to initialize
// Only runs when actually needed!
}
}
When to Use Lazy?
| Situation | Use Lazy? |
|---|---|
| Heavy initialization | β Yes |
| Rarely used bean | β Yes |
| Quick startup needed | β Yes |
| Critical core service | β No |
| Always needed at start | β No |
Global Lazy Mode
@SpringBootApplication
@Lazy // All beans are lazy now!
public class MyApp {
public static void main(String[] args) {
SpringApplication.run(MyApp.class);
}
}
π― Quick Summary
π IoC Container
βββ Manages all your beans
π¦ BeanFactory vs ApplicationContext
βββ Basic vs Full-featured (use AppContext!)
π§± Bean = Object managed by Spring
βββ Use @Component to register
π Lifecycle = Birth β Init β Use β Destroy
βββ Use @PostConstruct and @PreDestroy
π Scopes
βββ Singleton = One shared instance
βββ Prototype = Fresh copy each time
βββ Web = request, session, application
π Thread Safety
βββ Singletons need care with shared state!
π΄ Lazy Initialization
βββ Create beans only when needed
π Youβre Ready!
You now understand the heart of Spring! The IoC Container is your magical factory manager that:
- Creates beans from your recipes
- Connects them together automatically
- Manages their entire lifecycle
- Controls how many copies exist
- Decides when to create them
Remember: Spring does the heavy lifting so you can focus on building amazing apps!
Next up: Learn how Spring automatically connects beans with Dependency Injection!