Prototype Bean in Singleton — The Scoping Trap
Fast recall
Quick revision
Core answer
ObjectProvider (singleton-scoped itself) and call .getObject() every time you need a fresh instance. Alternatives: `@Lookup` methods (Spring generates a CGLIB subclass that overrides the method to fetch from the container), or injecting ApplicationContext and calling getBean(...) directly (service locator, not recommended). Not a valid fix: scoped proxies — those are for request/session scopes that have a well-defined lifecycle, not prototype.Whether you understand scope mismatch — prototype inside singleton — and know the correct resolution (ObjectProvider, @Lookup) without resorting to ApplicationContextAware
Thinking a scoped proxy fixes prototype-in-singleton; not realizing field-injected prototypes are shared for the singleton's entire lifetime
Compare ObjectProvider, @Lookup, and Provider<T> (JSR-330); explain why scoped proxies don't work for prototype
Interview-ready guide
Interview answer
Injecting a prototype-scoped bean into a singleton is one of Spring's most common traps. The developer expects a fresh instance on every use — that's why they chose prototype. But Spring injects the prototype exactly once during the singleton's construction and never again. The prototype becomes a de facto singleton.
Why it happens
- Singleton beans are created once and their dependencies are injected once
- When a prototype is a constructor or field dependency of a singleton, Spring resolves it at singleton creation time — one prototype instance, held forever
- Two concurrent requests share the prototype's mutable state — data corruption that appears intermittently
The fix: `ObjectProvider`
- Inject
ObjectProviderinstead of the bean itself — the provider is singleton-scoped - Call
.getObject()each time you need a fresh instance — Spring creates a new prototype on every call - Cleaner than
ApplicationContext.getBean(), which couples business code to the Spring API
The `@Lookup` alternative
- Annotate an abstract method with
@Lookup— Spring CGLIB-subclasses the singleton and overrides the method to return a new prototype instance on every call
Spring never calls @PreDestroy on prototype beans, regardless of how they were obtained. If the prototype holds resources, the calling code owns cleanup.
Prototype Bean in Singleton — The Scoping Trap
Direct Answer
Spring injects the prototype once during the singleton's construction, and the singleton holds that same instance forever — the prototype becomes a de facto singleton. The fix is to defer instantiation to the point of use. The idiomatic Spring 4+ solution is ObjectProvider<T> — inject ObjectProvider<MyPrototype> (singleton-scoped itself) and call .getObject() every time you need a fresh instance. Alternatives: @Lookup methods (Spring generates a CGLIB subclass that overrides the method to fetch from the container), or injecting ApplicationContext and calling getBean(...) directly (service locator, not recommended). Not a valid fix: scoped proxies — those are for request/session scopes that have a well-defined lifecycle, not prototype.
Common Mistakes & Pitfalls
Thinking a scoped proxy fixes prototype-in-singleton; not realizing field-injected prototypes are shared for the singleton's entire lifetime
Check your understanding
Answer these without looking back at the article.
- Why don't scoped proxies work for prototype-scoped beans?
- How does @Lookup generate a subclass, and what are its limitations?
- When would you prefer ObjectProvider over Provider<T> from JSR-330?
- Does Spring call @PreDestroy on prototype beans retrieved via ObjectProvider?
Related interview prep categories
1Looking for a structured roadmap?
Every module on this page is also part of the full Java backend interview track.