What Is a Bean Scope?
A bean's scope defines the lifecycle and visibility of the instance(s) the container creates for that bean definition — specifically, how many instances exist and how long each instance lives. Spring ships with six built-in scopes: singleton and prototype are available in any Spring context, while request, session, application, and websocket are only meaningful in a web-aware ApplicationContext because they tie a bean's lifetime to an HTTP or WebSocket concept. Choosing the wrong scope is a common source of subtle bugs, such as accidentally sharing mutable state across concurrent users.
Cricket analogy: A single trophy shared by the whole IPL league (singleton) behaves very differently from a fresh matchball issued for every single innings (prototype), just as bean scope determines whether one shared instance or many fresh instances exist.
Singleton and Prototype Scopes
Singleton, Spring's default scope, means the container creates exactly one instance of the bean per ApplicationContext, and every injection point receives a reference to that same shared instance — this is efficient but means singleton beans must be stateless or thread-safe, since concurrent requests will access the same object concurrently. Prototype scope creates a brand-new instance every time the bean is requested from the container or injected into another bean, which suits beans that hold per-use mutable state, but comes at the cost of the container not managing the prototype's full lifecycle — notably, @PreDestroy callbacks are never invoked for prototype beans.
Cricket analogy: A stadium's single floodlight system serves every match played there (singleton, shared and must handle concurrent games safely), while a fresh set of stumps is set up for every individual match (prototype, new state each time).
@Component
@Scope("singleton") // default, explicit here for clarity
public class ConfigCache {
private final Map<String, String> values = new ConcurrentHashMap<>(); // must be thread-safe
}
@Component
@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class ReportBuilder {
private final List<String> lines = new ArrayList<>(); // safe: a fresh instance per use
public void addLine(String line) {
lines.add(line);
}
}
@Service
public class ReportService {
private final ObjectProvider<ReportBuilder> reportBuilderProvider;
public ReportService(ObjectProvider<ReportBuilder> reportBuilderProvider) {
this.reportBuilderProvider = reportBuilderProvider;
}
public ReportBuilder newReport() {
// Explicitly requests a fresh prototype instance each call
return reportBuilderProvider.getObject();
}
}Web-Aware Scopes: Request, Session, and Application
In a web application, request scope creates one bean instance per HTTP request and discards it once the request completes, ideal for holding per-request state like a correlation ID or an accumulated validation error list. session scope creates one instance per HTTP session, persisting across multiple requests from the same user until the session expires, suitable for a shopping cart or wizard-style multi-step form state. application scope is effectively equivalent to a singleton but tied specifically to the ServletContext rather than the Spring ApplicationContext, useful in rare cases involving multiple Spring contexts within one servlet container.
Cricket analogy: A ball-by-ball commentary note is fresh for every single delivery and discarded once the over moves on (request scope), while a player's running tally of runs persists across the entire innings (session scope).
Scoped Proxies
Injecting a request- or session-scoped bean directly into a singleton bean is a common pitfall: the singleton is created once at startup, but the request/session bean's real instance doesn't exist until an HTTP request or session arrives, so the injection would fail. Spring solves this with scoped proxies (proxyMode = ScopedProxyMode.TARGET_CLASS or INTERFACES), where the singleton actually holds a lightweight proxy that, on every method call, looks up the current request or session's real bean instance and delegates to it — meaning the singleton always talks to a proxy, and the proxy transparently resolves to the correct instance based on the current thread's request context.
Cricket analogy: A commentary team injects a 'current striker' reference into their broadcast script before knowing who's actually batting; a scoped proxy is like a placeholder nameplate that's swapped for the real batsman's name the instant play begins.
Forgetting proxyMode when a singleton depends on a request- or session-scoped bean produces a startup or runtime error such as 'Scope 'request' is not active for the current thread' — this is one of the most common bean-scope mistakes in real Spring Boot applications, especially when refactoring a controller-level bean into a shared service.
- Bean scope controls how many instances of a bean exist and how long each instance lives.
- Singleton (the default) creates one shared instance per ApplicationContext; it must be stateless or thread-safe.
- Prototype creates a fresh instance on every request from the container, but the container does not track its full lifecycle afterward.
- Request, session, application, and websocket scopes are only meaningful in a web-aware ApplicationContext.
- Request scope lives for one HTTP request; session scope persists across a user's session.
- Injecting a request/session-scoped bean into a singleton requires a scoped proxy to avoid startup failures.
- ScopedProxyMode.TARGET_CLASS or INTERFACES makes the singleton hold a proxy that resolves to the correct instance per request.
Practice what you learned
1. What is Spring's default bean scope?
2. Why must singleton beans generally be stateless or thread-safe?
3. What happens to @PreDestroy callbacks for prototype-scoped beans?
4. Why is a scoped proxy needed when injecting a request-scoped bean into a singleton?
5. Which scope is tied to the ServletContext rather than the Spring ApplicationContext?
Was this page helpful?
You May Also Like
Spring Beans and Annotations
Understand what a Spring bean is, how stereotype annotations declare them, and how lifecycle and qualifier annotations control their behavior.
Dependency Injection Explained
Learn how Spring's IoC container supplies objects with the collaborators they need, instead of letting objects build those collaborators themselves.
Configuration Classes
Learn how @Configuration classes and @Bean methods provide explicit, programmatic bean wiring, and how to compose and conditionally activate them.
Component Scanning
Learn how Spring discovers annotated classes on the classpath and registers them as beans, and how to control scan scope with filters.
Related Reading
Related Study Notes in Web Development
Browse all study notesWebSockets Study Notes
Web Development · 30 topics
Web DevelopmentWebAssembly Study Notes
WebAssembly · 30 topics
Web DevelopmentgRPC Study Notes
Protocol Buffers · 30 topics
Web DevelopmentFlask Study Notes
Python · 30 topics
Web DevelopmentDjango Study Notes
Python · 30 topics
Web DevelopmentNext.js Study Notes
JavaScript · 30 topics