Bean Scopes
Learn how Spring manages the lifecycle and visibility of beans through scopes, focusing on singleton and prototype and when to use each.
Introduction
When the Spring container creates a bean, it also decides how many instances of that bean exist and how long each instance lives. This behavior is controlled by the bean's scope. By default, Spring assumes every bean should be shared as a single instance, but that is not always what you want. In this lesson you will learn about the two most common scopes, singleton and prototype, and how to pick the right one for a given class.
- What a bean scope controls
- How the default singleton scope behaves
- How to declare a prototype-scoped bean
- Why injecting a prototype bean into a singleton needs special handling
What Is a Bean Scope?
A scope defines the lifecycle boundary of a bean: how many objects the container creates for that bean definition, and when those objects are created and destroyed. Spring ships with several built-in scopes, but the two you will use constantly are singleton and prototype. Scope is declared with the @Scope annotation, or left unset to use the default.
Singleton Scope
Singleton is the default scope. For a given bean definition, the container creates exactly one instance, caches it, and returns that same instance for every subsequent request, whether the request comes from another bean's dependency or a direct call to getBean().
@Componentpublic class SingletonBean {
public SingletonBean() { System.out.println("SingletonBean instance created"); }}public class Main { public static void main(String[] args) { ApplicationContext context = new AnnotationConfigApplicationContext("com.example.app");
SingletonBean first = context.getBean(SingletonBean.class); SingletonBean second = context.getBean(SingletonBean.class);
System.out.println("Same instance? " + (first == second)); }}Click Run to see what this code prints.
Notice that the constructor only ran once. Both variables point to the exact same object in memory, which is why the equality check with == returns true.
Prototype Scope
Prototype scope tells the container to create a brand-new instance every single time the bean is requested, either through getBean() or through dependency injection. The container hands the object over and then stops tracking it; it will not call any destruction callback on a prototype bean.
@Component@Scope("prototype")public class PrototypeBean {
public PrototypeBean() { System.out.println("PrototypeBean instance created"); }}PrototypeBean first = context.getBean(PrototypeBean.class);PrototypeBean second = context.getBean(PrototypeBean.class);
System.out.println("Same instance? " + (first == second));Click Run to see what this code prints.
This time the constructor ran twice, once for each getBean() call, and the two references point to different objects. Prototype scope is a good fit for beans that hold mutable, request-specific, or short-lived state.
Injecting a Prototype into a Singleton
A common trap: if you inject a prototype bean as a field into a singleton, Spring resolves that dependency only once, when the singleton is created. From then on the singleton keeps reusing the same prototype instance, which defeats the purpose of prototype scope. To get a fresh prototype instance on every use, ask the container for it explicitly, for example through an ObjectFactory or a scoped proxy.
@Componentpublic class ReportGenerator {
private final ObjectFactory<PrototypeBean> prototypeFactory;
public ReportGenerator(ObjectFactory<PrototypeBean> prototypeFactory) { this.prototypeFactory = prototypeFactory; }
public void generate() { PrototypeBean freshInstance = prototypeFactory.getObject(); // freshInstance is a new PrototypeBean every time generate() runs }}Other Available Scopes
Spring also defines web-aware scopes that only make sense inside a web application context, because they depend on an active HTTP request or session.
| Scope | Lifetime |
|---|---|
| singleton | One instance per Spring container (default) |
| prototype | A new instance on every request for the bean |
| request | One instance per HTTP request (web apps only) |
| session | One instance per HTTP session (web apps only) |
| application | One instance per ServletContext (web apps only) |
Common Mistakes
- Assuming @Scope("prototype") means Spring will destroy the bean automatically — the container does not manage prototype destruction.
- Field-injecting a prototype bean into a singleton and expecting a new instance every time it is used.
- Using prototype scope for beans that do not actually need per-request state, adding unnecessary object creation overhead.
- Forgetting that request and session scopes require a web-aware ApplicationContext to work.
Best Practices
- Default to singleton scope; it is the right choice for the vast majority of stateless services, repositories, and controllers.
- Reach for prototype scope only when a bean genuinely needs to hold mutable or per-use state.
- Use ObjectFactory<T> or a scoped proxy when a singleton needs a fresh prototype instance on demand.
- Keep singleton beans stateless and thread-safe since the same instance is shared across every thread that uses it.
Frequently Asked Questions
Singleton. If you do not add @Scope, the container creates and caches exactly one instance per bean definition.
No. Once a prototype bean is handed to the caller, Spring stops managing its lifecycle, including destruction callbacks. Cleanup becomes the caller's responsibility.
Not exactly. The singleton pattern guarantees one instance per JVM classloader; a Spring singleton guarantees one instance per bean definition within a single ApplicationContext, so multiple contexts can each hold their own instance.
Key Takeaways
- Bean scope controls how many instances the container creates and how long they live.
- Singleton is the default: one shared, cached instance per container.
- Prototype creates a new instance on every request, and Spring does not manage its destruction.
- Injecting a prototype into a singleton by default freezes it into a single instance; use ObjectFactory or scoped proxies to avoid that.
- Request, session, and application scopes exist for web applications only.
Summary
Bean scopes give you control over how Spring shares or duplicates the objects it manages. Singleton scope is the sensible default for stateless components, while prototype scope exists for the cases where a fresh, isolated instance is needed each time. Understanding the interaction between the two, especially when injecting a prototype into a singleton, will save you from subtle state-sharing bugs. Next, you will look at what happens during a bean's life from creation to destruction.