What scopes exist in Spring
In the Spring Framework, bean scopes are partitioned into two architectural categories: Universal Scopes (available in any Java application, including CLI, batch, and desktop) a...
🟢 Junior Level
1. Classification of Scopes in Spring
In the Spring Framework, bean scopes are partitioned into two architectural categories: Universal Scopes (available in any Java application, including CLI, batch, and desktop) and Web-Aware Scopes (available only within web-aware contexts such as Spring MVC and Spring Boot Web).
Summary Table of All Standard Scopes
| Scope Name | Environment | Lifecycle Boundary & Instance Cardinality |
|---|---|---|
singleton (Default) |
Universal | Exactly 1 instance per ApplicationContext. Exists until the container closes. |
prototype |
Universal | A new instance is created on every injection or getBean() invocation. |
request |
Web / Servlet | 1 instance per individual HTTP Request. Destroyed when the request completes. |
session |
Web / Servlet | 1 instance per HTTP Session. Lives as long as the user session remains active. |
application |
Web / Servlet | 1 instance per ServletContext. Shared across all servlets in the container. |
websocket |
Web / WebSocket | 1 instance per WebSocket session lifecycle. |
2. Declaration Syntax in Modern Spring Boot
In modern Spring Boot applications, convenient composed stereotype annotations replace verbose XML or string-based scope declarations:
package com.example.scopes;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import org.springframework.web.context.annotation.ApplicationScope;
import org.springframework.web.context.annotation.RequestScope;
import org.springframework.web.context.annotation.SessionScope;
// 1. Singleton Scope (Default - annotation optional)
@Component
public class CatalogService { }
// 2. Prototype Scope
@Component
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class HeavyCalculationTask { }
// 3. Request Scope (Alias for @Scope(value = "request", proxyMode = ScopedProxyMode.TARGET_CLASS))
@Component
@RequestScope
public class RequestAuditContext { }
// 4. Session Scope (Alias for @Scope(value = "session", proxyMode = ScopedProxyMode.TARGET_CLASS))
@Component
@SessionScope
public class UserShoppingCart { }
// 5. Application Scope (Alias for @Scope(value = "application", proxyMode = ScopedProxyMode.TARGET_CLASS))
@Component
@ApplicationScope
public class ServletContextMetrics { }
🟡 Middle Level
1. Internal Storage of Web Scopes
Web-aware scopes rely on Spring’s RequestContextHolder, which stores the current request’s RequestAttributes inside a ThreadLocal:
requestScope:- The bean instance is bound to the current servlet request:
HttpServletRequest.setAttribute(name, bean). - When the HTTP thread finishes executing, the servlet container cleans up request attributes, and Spring triggers registered destruction callbacks.
- The bean instance is bound to the current servlet request:
sessionScope:- The bean instance is stored in the standard servlet session:
HttpSession.setAttribute(name, bean). - Enables persisting user-specific state (shopping carts, user authentication tokens, locale preferences) across multiple HTTP requests from the same client.
- The bean instance is stored in the standard servlet session:
applicationScope vssingleton:singleton: Bound to a single SpringApplicationContext.application: Bound to the web container’sServletContext.- Architectural Difference: In enterprise setups where multiple
DispatcherServletinstances run inside a single web container, each servlet possesses its own childApplicationContextwith separatesingletonbeans, but they all share the exact same@ApplicationScopebean.
2. Scoped Proxy Modes: ScopedProxyMode
When injecting a short-lived bean (request, session) into a long-lived singleton bean, you must configure proxyMode:
ScopedProxyMode Options:
├── DEFAULT / NO:
│ └── No proxy is generated. Injecting into a singleton causes Scoped Mismatch (freezes the instance).
├── TARGET_CLASS (Default for @RequestScope / @SessionScope):
│ └── Generates a CGLIB dynamic subclass proxy. Works on any concrete class.
└── INTERFACES:
└── Generates a JDK Dynamic Proxy. Requires the target bean to implement an interface.
@Bean
@Scope(value = WebApplicationContext.SCOPE_SESSION, proxyMode = ScopedProxyMode.TARGET_CLASS)
public UserSessionContext userSessionContext() {
return new UserSessionContext();
}
🔴 Senior Level
1. Spring Cloud @RefreshScope
In cloud-native microservices, configuration properties change dynamically (via Spring Cloud Config Server, Consul, or Vault) without requiring a JVM or container restart:
@Component
@RefreshScope
@ConfigurationProperties(prefix = "payment.gateway")
public class PaymentGatewayProperties {
private String apiUrl;
private int timeoutMs;
// Getters and setters
}
Under the Hood Mechanics of @RefreshScope:
- Spring Cloud registers a specialized
RefreshScopeimplementation oforg.springframework.beans.factory.config.Scope. - The bean is wrapped in a dynamic CGLIB proxy backed by a
RefreshScopeinterceptor. - Bean instances are stored in an internal cache (
BeanLifecycleDecoratorCache). - When a
/actuator/refreshHTTP endpoint is invoked (or a Kafka/RabbitMQRefreshEventis received), theRefreshScopeclears its internal instance cache. - On the very next method call through the CGLIB proxy, the interceptor detects a cache miss, re-reads updated properties from the Spring
Environment, and instantiates a brand-new target instance!
2. Clustered Microservice Hazards: Native @SessionScope
In modern containerized deployments (Kubernetes pods behind load balancers):
HTTP Request 1 (Login) ──► [Load Balancer] ──► [Pod 1] (Session stored in Pod 1 heap)
HTTP Request 2 (Checkout) ──► [Load Balancer] ──► [Pod 2] (Session NOT FOUND ──► 401 Unauthorized!)
Architectural Vulnerability:
Default @SessionScope stores state inside the local JVM heap of a single Tomcat instance. In multi-pod deployments without sticky sessions, subsequent requests fail.
Production Solution: Spring Session + Redis
Integrate Spring Session backed by a shared Redis cluster (@EnableRedisHttpSession):
- The HTTP session state is serialized and stored in Redis.
- Every pod in the Kubernetes cluster retrieves and mutates the exact same shared session, rendering
@SessionScopehorizontally scalable.
3. The SimpleThreadScope Hazard in Thread Pools
Spring provides an out-of-the-box SimpleThreadScope bound to ThreadLocal, but intentionally does not enable it by default:
@Configuration
public class ThreadScopeConfig {
@Bean
public static CustomScopeConfigurer customScopeConfigurer() {
CustomScopeConfigurer configurer = new CustomScopeConfigurer();
configurer.addScope("thread", new SimpleThreadScope());
return configurer;
}
}
[!WARNING] Why
SimpleThreadScopeis Dangerous in Enterprise Web Applications:
- Thread Pool Contamination: Application servers (Tomcat, Undertow) and async executors (
ThreadPoolTaskExecutor) reuse threads. When a thread finishes processing a request and returns to the pool, itsThreadLocalis not automatically cleared. The next request handled by that worker thread inadvertently accesses dirty state from a previous user!- No Destruction Callbacks:
SimpleThreadScopedoes not support destruction callbacks;@PreDestroyandDisposableBean.destroy()are never invoked, causing native memory leaks.
4 Tricky Questions
1. What is the fundamental difference between singleton scope and application scope?
Answer:
A singleton bean exists as a single instance per Spring ApplicationContext.
An application scoped bean (@ApplicationScope) exists as a single instance per ServletContext of the Java web container.
In enterprise deployments where multiple DispatcherServlet contexts reside within a single web application (e.g., legacy multi-module WAR deployments), each servlet owns its own child ApplicationContext with its own isolated singleton beans. However, beans marked with @ApplicationScope are stored directly in ServletContext.setAttribute() and are shared globally across all servlet contexts in that web application.
2. How does the composed annotation @RequestScope work under the hood, and why is ScopedProxyMode.TARGET_CLASS enabled by default?
Answer:
@RequestScope is a composed meta-annotation defined as:
@Scope(WebApplicationContext.SCOPE_REQUEST)
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface RequestScope {
@AliasFor(annotation = Scope.class)
ScopedProxyMode proxyMode() default ScopedProxyMode.TARGET_CLASS;
}
By defaulting to ScopedProxyMode.TARGET_CLASS, Spring automatically wraps the bean in a CGLIB dynamic proxy. This allows request-scoped beans to be injected safely into singleton controllers and services at startup. When client code invokes a method on the proxy, the proxy intercepts the call and dynamically looks up the active bean instance from RequestContextHolder (ThreadLocal) for the current HTTP worker thread.
3. How does Spring Cloud’s @RefreshScope dynamically update configuration without restarting the JVM?
Answer:
Spring Cloud wraps @RefreshScope beans in a dynamic CGLIB proxy with a custom interceptor. Bean instances are stored in an internal cache managed by the RefreshScope class.
When an /actuator/refresh request is triggered:
- Spring Cloud publishes a
RefreshEventand reloads thePropertySourcehierarchy. - The
RefreshScopeinvalidates and clears its internal cache of target bean instances. - The next time application code invokes any method on the CGLIB proxy, the proxy detects that the cached target instance is missing.
- It calls
createBeanInstance()to construct a brand-new bean instance, binding the updated environment configuration properties, and caches it.
4. Why is using Spring’s built-in SimpleThreadScope considered hazardous in production web applications?
Answer:
SimpleThreadScope binds bean instances to the current thread using ThreadLocal.
In modern web applications, incoming requests are handled by thread pools (e.g., Tomcat worker threads). When a thread finishes servicing a request and returns to the pool, SimpleThreadScope does not automatically remove the ThreadLocal entries. When that thread is later assigned to process a request from a different user, it reuses the dirty, leftover bean instance from the previous request, causing data corruption, security breaches, and memory leaks. Furthermore, SimpleThreadScope does not support destruction callbacks (@PreDestroy is never called).
🎯 Interview Cheat Sheet
30-Second Elevator Pitch
“Spring provides 6 standard bean scopes:
- Universal:
singleton(1 perApplicationContext, default) andprototype(new instance per request).- Web-Aware:
request(1 per HTTP request),session(1 per HTTP session),application(1 perServletContext), andwebsocket(1 per WebSocket connection).In modern Spring Boot, composed annotations (
@RequestScope,@SessionScope,@ApplicationScope) automatically configureScopedProxyMode.TARGET_CLASSto allow safe injection into singletons via CGLIB dynamic proxies. In distributed microservice environments,@RefreshScopeenables hot-reloading of configuration, and Spring Session + Redis replaces node-local in-memory session scope.”
Red Flags & Pitfalls (DO NOT Say)
- ❌ “Web scopes can be used in standard command-line Java applications.” (Web scopes require a web-aware
WebApplicationContextandRequestContextHolder). - ❌ “In clustered microservices,
@SessionScopebeans synchronize across nodes automatically.” (Standard@SessionScopeis node-local; you must use Spring Session with Redis). - ❌ “The
@RefreshScopeannotation restarts the entire Spring Boot ApplicationContext.” (It only clears the proxy’s instance cache, re-instantiating only the affected beans). - ❌ “Singleton scope and application scope are the exact same thing.” (Singleton is 1 per
ApplicationContext; application is 1 perServletContext).
Complete Scope Comparison Matrix
Scope Feature Comparison:
┌─────────────┬─────────────┬────────────────────────────────┬───────────────────────────┐
│ Scope │ Environment │ Storage Mechanism │ Scoped Proxy Required │
│ │ │ │ in Singleton? │
├─────────────┼─────────────┼────────────────────────────────┼───────────────────────────┤
│ singleton │ Universal │ DefaultSingletonBeanRegistry │ No │
│ prototype │ Universal │ Not cached (Created on demand) │ Use ObjectProvider<T> │
│ request │ Web │ HttpServletRequest attributes │ Yes (TARGET_CLASS) │
│ session │ Web │ HttpSession / Redis Session │ Yes (TARGET_CLASS) │
│ application │ Web │ ServletContext attributes │ Yes (TARGET_CLASS) │
│ websocket │ Web │ WebSocketSession attributes │ Yes (TARGET_CLASS) │
│ refresh │ Cloud │ RefreshScope internal cache │ Auto-proxied by framework │
└─────────────┴─────────────┴────────────────────────────────┴───────────────────────────┘