Spring Boot Bean scopes
Default scope: singleton
(one instance per Spring ApplicationContext). Spring reuses the same bean for every injection/call.
Note: This is not the GoF Singleton patternโeach ApplicationContext has its own instance.
Core scopes (available everywhere)
Scope | What it means | Typical use |
---|---|---|
singleton (default)
|
One instance per ApplicationContext
|
Services, controllers, repositories (stateless) |
prototype |
New instance every injection / getBean()
|
Stateful helpers, per-use objects |
Web scopes (need a web-aware context: Spring MVC/WebFlux)
Scope | What it means | Typical use |
---|---|---|
request |
One instance per HTTP request | Request-scoped DTO, per-request context |
session |
One instance per HTTP session | Shopping cart, user preferences |
application |
One per ServletContext
|
Cross-servlet shared state (rare) |
websocket |
One per WebSocket session | Per-socket state in STOMP/websocket apps |
How to set a scope
Annotation-based components
import org.springframework.stereotype.Component;
import org.springframework.context.annotation.Scope;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
@Component
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) // or "prototype"
public class MyPrototype {}
@Bean
methods
import org.springframework.context.annotation.*;
import org.springframework.web.context.WebApplicationContext;
@Configuration
public class AppConfig {
@Bean
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
MyPrototype proto() { return new MyPrototype(); }
@Bean
@Scope(value = WebApplicationContext.SCOPE_REQUEST,
proxyMode = ScopedProxyMode.TARGET_CLASS) // important when injecting into singletons
RequestScopedBean reqBean() { return new RequestScopedBean(); }
}
Convenience annotations (web)
import org.springframework.web.context.annotation.RequestScope;
import org.springframework.web.context.annotation.SessionScope;
@RequestScope
@Component
class PerRequestCtx {}
@SessionScope
@Component
class Cart {}
Injecting non-singletons into singletons (the โgotchaโ)
A singleton bean is created at startup; if it receives a prototype
/request
bean directly, that dependency is resolved once. Use one of:
-
Scoped proxy
@Component
@Scope(value = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS)
class RequestUserContext {}
@Component
class ServiceA {
private final RequestUserContext ctx; // injected as a proxy โ resolves per request
ServiceA(RequestUserContext ctx) { this.ctx = ctx; }
}
-
Provider/ObjectFactory (create on demand)
import org.springframework.beans.factory.ObjectProvider;
@Component
class ServiceB {
private final ObjectProvider<MyPrototype> provider;
ServiceB(ObjectProvider<MyPrototype> provider) { this.provider = provider; }
void doWork() {
MyPrototype p = provider.getObject(); // new instance each call
}
}
Best practices
- Keep most beans stateless singletons (thread-safe).
- Use
prototype
sparingly; note that Spring does not manage its full lifecycle after creation (no destroy callbacks). - For web scopes, prefer
@RequestScope
/@SessionScope
and scoped proxies when injecting into singletons. - Avoid storing large objects in session/request beans.
(Advanced) Custom/thread scope
Spring has a SimpleThreadScope
you can register:
import org.springframework.context.support.SimpleThreadScope;
import org.springframework.beans.factory.config.CustomScopeConfigurer;
@Bean
public static CustomScopeConfigurer customScopes() {
CustomScopeConfigurer c = new CustomScopeConfigurer();
c.addScope("thread", new SimpleThreadScope());
return c;
}
// Then: @Scope("thread")
If you tell me your exact use case (e.g., โneed per-request user context in a serviceโ), Iโll show the minimal wiring with proxies or providers.