What are Spring bean scopes, and when would you use something other than singleton?

8 minintermediatebean-scopessingletonprototype

Quick Answer

Singleton (the default) means exactly one shared instance per Spring container, reused for every injection point — appropriate for stateless services. Prototype creates a brand-new instance every time the bean is requested — appropriate for stateful, non-thread-safe objects. Web-aware scopes (request, session, application) tie a bean's lifetime to an HTTP request, session, or the ServletContext respectively, used for holding per-request or per-user state cleanly.

Detailed Answer

Spring bean scope controls how many instances of a bean definition exist and how long each one lives:

  • singleton (the default): exactly one instance per Spring container, shared by every injection point. Appropriate for stateless components — most @Service/@Repository beans fit this naturally, since they hold no per-request mutable state.
@Service // singleton by default
class OrderService { }
  • prototype: a new instance is created every time the bean is requested (injected or fetched via getBean()). Appropriate for objects that hold mutable, non-thread-safe per-use state.
@Component
@Scope("prototype")
class ReportBuilder { /* accumulates mutable state per report */ }
  • request (web-aware): one instance per HTTP request — useful for holding request-scoped data cleanly instead of threading it through method parameters.
  • session (web-aware): one instance per HTTP session — useful for per-user state like a shopping cart.
  • application (web-aware): one instance per ServletContext — similar to singleton but scoped to the web application rather than the Spring container specifically (relevant when multiple contexts share a servlet context).

A common gotcha: injecting a prototype-scoped bean into a singleton-scoped bean via normal field/constructor injection only resolves it once, at the singleton's creation time — every subsequent use gets the same prototype instance, defeating the purpose. Fixing this requires a scoped proxy (proxyMode = ScopedProxyMode.TARGET_CLASS) or looking the bean up via ObjectFactory/ObjectProvider each time it's actually needed, so a fresh prototype instance is fetched per use.

Rule of thumb: default to singleton; reach for prototype (or a web-aware scope) only when a bean genuinely needs per-use or per-request/session mutable state.

Related Resources