Difference between Singleton and Prototype Scope?
4. Prototype -> clean resources yourself 5. Avoid cycles in Prototype 6. If you just need an object without DI, @PostConstruct and proxying - a regular new is faster than Protot...
Junior Level
| Singleton | Prototype | |
|---|---|---|
| Instances | One | New each time |
| @PreDestroy | Called | NOT called |
| When created | On startup | On request |
@Service // Singleton
public class A { }
@Scope("prototype")
@Service
public class B { }
A a1 = context.getBean(A.class);
A a2 = context.getBean(A.class);
a1 == a2 // -> true (same object!)
B b1 = context.getBean(B.class);
B b2 = context.getBean(B.class);
b1 == b2 // -> false (different objects!)
Middle Level
Singleton
// By default!
// Stored in singletonObjects cache
// -> Fast access, not created each time
// Must be Stateless!
// -> All threads use the same object
// -> Do not store data in fields!
Prototype
// Each request -> new object
// Full lifecycle: constructor -> @PostConstruct
// BUT: @PreDestroy is NOT called!
// You are responsible for cleanup:
PrototypeBean bean = context.getBean(PrototypeBean.class);
try {
// usage
} finally {
bean.cleanup(); // Manually!
}
Prototype in Singleton Problem
// Prototype "freezes"
@Service
public class SingletonService {
@Autowired PrototypeBean proto; // Created ONCE!
}
// Why: Singleton is created once, and all its dependencies are injected
// at creation time. PrototypeBean is created once during injection and
// then reused - Spring does not create a new instance on each
// access to the singleton bean.
// ObjectProvider
@Service
public class SingletonService {
@Autowired ObjectProvider<PrototypeBean> provider;
public void process() {
PrototypeBean proto = provider.getObject(); // New!
}
}
Senior Level
Circular Dependencies
Singleton:
-> Spring can resolve via earlySingletonObjects
Prototype:
-> Unresolvable in principle!
-> A -> B -> A -> infinite recursion
-> BeanCurrentlyInCreationException
Performance Overhead
Singleton:
-> Created once
-> Fast access from cache
Prototype:
-> Full creation cycle each time
-> Reflection, BPP, @PostConstruct
-> On frequent requests -> slow!
Memory Leaks
Prototype with resources:
-> Opened file/connection
-> Spring does not call @PreDestroy
-> Resource not released -> leak!
Solution:
-> try-finally with cleanup()
-> Or BeanPostProcessor for tracking
Production Experience
Real scenario: Prototype leak
In a scenario where each Prototype bean opens a connection:
10,000 requests/sec -> 10,000 connections -> DB crashes
Solution: Singleton + ObjectPool
Best Practices
- Singleton - 95% of cases (Stateless!)
- Prototype - heavy stateful objects
- ObjectProvider - Prototype in Singleton
- Prototype -> clean resources yourself
- Avoid cycles in Prototype
- If you just need an object without DI, @PostConstruct and proxying - a regular
newis faster than Prototype from Spring context.
Summary for Senior
- Singleton = cache, Stateless, @PreDestroy works
- Prototype = new each time, @PreDestroy does NOT work
- Prototype in Singleton -> ObjectProvider
- Cycles -> unresolvable for Prototype
- Resources -> clean manually in Prototype
- Performance -> Prototype is more expensive than Singleton
Interview Cheat Sheet
Must know:
- Singleton = one instance, cached; Prototype = new on each
getBean() - @PreDestroy is only called for Singleton, for Prototype - NEVER
- Prototype in Singleton = problem: Prototype is created once and “freezes”
- Circular dependencies are resolvable for Singleton (via earlySingletonObjects), but NOT for Prototype
- Performance: Prototype is more expensive - full creation cycle each time (reflection, BPP, @PostConstruct)
- Resources in Prototype - leak, clean manually via try-finally
- If you just need an object without DI - use
new, not Prototype
Common follow-up questions:
- How to get a new Prototype inside a Singleton? -> ObjectProvider.getObject()
- Why are circular dependencies unresolvable for Prototype? -> Infinite creation recursion, Spring throws BeanCurrentlyInCreationException
- Where is Singleton stored? -> singletonObjects cache (ConcurrentHashMap)
- When is Prototype justified? -> Heavy stateful objects, when Singleton + ThreadLocal cannot be used
Red flags (DO NOT say):
- “@PreDestroy works for Prototype” - does not work
- “Singleton is created on each request” - created once
- “Prototype is faster than Singleton” - opposite, full cycle each time
- “Cycles in Prototype are resolved via @Lazy” - unresolvable in principle
Related topics:
- [[11. What scopes exist in Spring]]
- [[13. What is a proxy in Spring]]
- [[19. How to solve the self-invocation problem]]