Bean scope questions look simple until the follow-ups arrive. Naming singleton and prototype earns nothing on its own; interviewers are checking whether you understand what "one instance per container" really means, why a singleton shared across threads is a concurrency risk, and how to correctly get a fresh prototype from inside a singleton. This set covers the scope questions asked in intermediate rounds, each with a spoken answer and the trap that usually follows.
Why interviewers ask about bean scopes
Scope decides how many instances of a bean exist and how long they live, which directly controls state, memory and thread safety. Choosing the wrong scope produces some of the most confusing bugs in Spring — shared mutable state on a singleton, or a prototype that mysteriously never changes. Interviewers ask because scope reveals whether you think about lifetime and sharing, not just wiring.
Q1. What bean scopes does Spring Boot support?
Two scopes exist in any Spring application — singleton (one instance per container, the default) and prototype (a new instance every time the bean is requested). A web application adds four more: request, session, application and websocket.
You set a non-default scope with @Scope. The names describe the lifetime: a request-scoped bean lives for one HTTP request, a session-scoped bean for one user session, an application-scoped bean for the ServletContext lifetime, and a websocket-scoped bean for a WebSocket session.
@Component
@Scope("prototype")
class ShoppingCart { /* a new instance per injection point / lookup */ }
Interview note: Follow-up: "which of these need a web context to work?" Request, session, application and websocket — asking for them outside a web application throws, because there is no request or session to bind the bean to.
Q2. What is the difference between singleton and prototype scope?
A singleton is created once per container, cached, and shared by every dependent — the same object everywhere. A prototype is created fresh each time it is requested or injected, so each holder gets its own instance. Singletons are eagerly created at startup by default; prototypes are created lazily on demand.
The lifecycle difference matters in interviews: the container manages a singleton fully, including destroy callbacks on shutdown, but only manages a prototype up to creation — it never runs destroy callbacks for prototypes. Use singleton for stateless services, prototype for objects that carry per-use mutable state.
Interview note: Trap: "does the container call
@PreDestroyon a prototype?" No — once it hands over the instance it keeps no reference, so cleanup is the caller's job. Linking scope to the destroy-callback rule signals real depth.
Q3. Is a Spring singleton the same as the singleton design pattern?
No. The Gang of Four singleton guarantees one instance per JVM/classloader, enforced in the class itself. A Spring singleton is one instance per Spring ApplicationContext — start two contexts and you get two instances. Spring's scope is about container-managed sharing, not JVM-wide uniqueness.
This distinction is a favourite because candidates parrot "singleton means one object" without qualifying "per container." In tests or multi-context setups the difference becomes visible, and knowing it shows you understand where the guarantee actually holds.
Interview note: Follow-up: "so how many instances if two contexts each define the bean?" Two — one per context. The uniqueness is scoped to the container, full stop.
Q4. Are singleton beans thread-safe?
No. Spring shares one singleton instance across every thread, but it does nothing to synchronize access. Any mutable instance field on a singleton is a shared-state race condition. The standard practice is to keep singletons stateless, or to guard mutable state explicitly.
This is why Spring services and repositories are typically stateless, pushing per-request data through method parameters or request-scoped beans instead of fields. When a singleton genuinely needs mutable state, use thread-safe constructs or scope the state to the request.
@Service
class CounterService {
private int count; // BUG: shared mutable state on a singleton
public void increment() { count++; } // not atomic, races across threads
}
Interview note: Trap: "how do you make per-request state safe on a singleton service?" Do not store it on the singleton — pass it as a parameter, or inject a request-scoped bean via a scoped proxy. Adding a lock is usually the wrong answer for request data.
Q5. What is the singleton-holding-prototype problem, and how do you fix it?
A singleton is created once, so any prototype injected into it as a normal field is resolved exactly once and cached with the singleton — you keep getting the same prototype instance, silently defeating prototype scope. The fixes are @Lookup method injection, an injected ObjectProvider<T> whose getObject() you call per use, or a scoped proxy with proxyMode = TARGET_CLASS.
The root cause is timing: injection happens when the singleton is built, and the singleton is only built once, so the prototype is never re-requested. Each fix defers resolution to call time instead of injection time.
@Component
class OrderProcessor {
@Autowired
private ObjectProvider<ShoppingCart> cartProvider; // prototype provider
void process() {
ShoppingCart cart = cartProvider.getObject(); // fresh prototype each call
}
}
Alternatively, mark the prototype with a scoped proxy so Spring injects a proxy that fetches a new target on each method call:
@Component
@Scope(value = "prototype", proxyMode = ScopedProxyMode.TARGET_CLASS)
class ShoppingCart { }
Interview note: Follow-up: "which fix would you pick?"
ObjectProviderfor explicit, readable lazy access; a scoped proxy when you want callers to use the bean transparently;@Lookupfor a container-generated factory method. All three move resolution to call time — that is the point.
Q6. What is a scoped proxy and when do you need one?
A scoped proxy is a lightweight stand-in that Spring injects in place of a shorter-lived bean. When a longer-lived bean (a singleton) depends on a shorter-lived one (request, session, or prototype), the proxy forwards each call to the correct current instance. Without it, the shorter-lived bean would be resolved once and frozen.
You enable it with proxyMode = ScopedProxyMode.TARGET_CLASS (CGLIB proxy of the class) or INTERFACES (JDK proxy of its interfaces). It is exactly what makes injecting a request-scoped bean into a singleton controller work correctly.
@Component
@Scope(value = "request", proxyMode = ScopedProxyMode.TARGET_CLASS)
class RequestContext { /* one real instance per HTTP request, behind a proxy */ }
Interview note: Trap: "why does a request-scoped bean need a proxy to be injected into a singleton?" The singleton exists once, at startup, when no request exists — the proxy defers to the live request instance on every call, so there is a real bean by the time a method is invoked.
Q7. What are the web scopes and what shortcut annotations exist?
request lives for one HTTP request, session for one user session, application for the ServletContext, and websocket for a WebSocket session. Spring provides shortcut annotations @RequestScope, @SessionScope and @ApplicationScope that combine @Scope with a sensible default proxy mode so you do not spell out the value and proxyMode by hand.
These shortcuts are the idiomatic way to declare web scopes because they enable a scoped proxy automatically, which is almost always what you want when injecting into a singleton.
@Component
@RequestScope // == @Scope(value="request", proxyMode=TARGET_CLASS)
class UserRequestInfo { }
Interview note: Follow-up: "difference between session and application scope?" Session is per user session — each logged-in user gets their own instance; application is one instance for the whole ServletContext, shared across all users and sessions.
Q8. Why is singleton the default scope, and when would you change it?
Singleton is the default because most beans — services, repositories, controllers, configuration — are stateless, so one shared instance is correct and cheapest in both memory and construction time. You change scope only when a bean must carry state that cannot be shared: prototype for per-use mutable objects, request/session for per-request or per-user state.
The design principle behind the default is "stateless by default, scoped by exception." If you find yourself reaching for prototype constantly, it usually signals state that should have been a method parameter or a dedicated request-scoped holder.
Interview note: Trap: "you made a service prototype to avoid a threading bug — is that right?" Usually no. The fix is to remove the mutable field from the singleton, not to multiply instances. Prototype hides the smell rather than removing it.
How to prepare
Build the singleton-holding-prototype demo from Q5 and prove it to yourself: inject a prototype as a plain field, print its identity hash across calls, watch it stay identical, then switch to ObjectProvider and watch it change. That five-minute experiment turns the most-asked scope follow-up into something you have seen rather than memorized. Do the same with a request-scoped bean behind a proxy injected into a singleton controller.
Ground the container concepts on the Spring Boot learning path, and read this alongside bean lifecycle and dependency injection — scope, lifetime and injection are almost always tested as a single thread of questions. A mock interview that pushes from "name the scopes" into "now fix this singleton" is the quickest way to find and close the gap in your explanation.
Frequently Asked Questions
What are the bean scopes available in Spring Boot?
Is a singleton bean one per JVM?
What is the singleton-holding-prototype problem?
Are singleton beans thread-safe?
Why is singleton the default scope in Spring?
Want to Build Your Career in Java Full Stack with AI?
Join CodeBegun and train with working industry engineers — See the Java Full Stack course in Hyderabad

