How do I manage bean scope in Spring?

In Spring, bean scope controls how many instances of a bean Spring creates and how long those instances live.

By default, Spring beans are singleton scoped, meaning Spring creates one shared instance per ApplicationContext.


Common Spring Bean Scopes

Scope Meaning
singleton One shared instance per Spring container
prototype A new instance every time the bean is requested
request One instance per HTTP request
session One instance per HTTP session
application One instance per ServletContext
websocket One instance per WebSocket session

The most commonly used scopes are:

  • singleton
  • prototype
  • request
  • session

1. Singleton Scope

singleton is the default scope.

import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;

@Service
@Scope("singleton")
public class UserService {
}

This is equivalent to:

import org.springframework.stereotype.Service;

@Service
public class UserService {
}

Spring creates only one UserService object, and every injection point receives the same instance.


Example

@Service
public class CounterService {

    private int count = 0;

    public int increment() {
        return ++count;
    }
}

Because this bean is singleton scoped, the count field is shared across the application.

That means singleton beans should usually be stateless, especially in web applications.

Prefer this:

@Service
public class PriceCalculator {

    public BigDecimal calculatePrice(BigDecimal amount) {
        return amount.multiply(new BigDecimal("1.10"));
    }
}

Avoid storing request-specific or user-specific data in singleton beans.


2. Prototype Scope

A prototype bean creates a new instance every time Spring is asked for the bean.

import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

@Component
@Scope("prototype")
public class ReportBuilder {

    private String title;

    public void setTitle(String title) {
        this.title = title;
    }

    public String build() {
        return "Report: " + title;
    }
}

Each direct request to Spring for ReportBuilder creates a new object.


Prototype with @Bean

You can also define prototype scope on a @Bean method:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;

@Configuration
public class AppConfig {

    @Bean
    @Scope("prototype")
    public ReportBuilder reportBuilder() {
        return new ReportBuilder();
    }
}

3. Important: Prototype Inside Singleton

A common surprise is this:

@Service
public class ReportService {

    private final ReportBuilder reportBuilder;

    public ReportService(ReportBuilder reportBuilder) {
        this.reportBuilder = reportBuilder;
    }
}

If ReportService is singleton and ReportBuilder is prototype, Spring injects one prototype instance when ReportService is created.

It does not automatically create a new ReportBuilder every time you use it.


Correct Way: Use ObjectProvider

If a singleton needs a fresh prototype instance on demand, use ObjectProvider.

import org.springframework.beans.factory.ObjectProvider;
import org.springframework.stereotype.Service;

@Service
public class ReportService {

    private final ObjectProvider<ReportBuilder> reportBuilderProvider;

    public ReportService(ObjectProvider<ReportBuilder> reportBuilderProvider) {
        this.reportBuilderProvider = reportBuilderProvider;
    }

    public String createReport(String title) {
        ReportBuilder builder = reportBuilderProvider.getObject();
        builder.setTitle(title);
        return builder.build();
    }
}

Now each call to getObject() returns a new prototype instance.


4. Request Scope

request scope creates one bean instance per HTTP request.

This is useful in Spring MVC applications for request-specific data.

import org.springframework.stereotype.Component;
import org.springframework.web.context.annotation.RequestScope;

@Component
@RequestScope
public class RequestContext {

    private String correlationId;

    public String getCorrelationId() {
        return correlationId;
    }

    public void setCorrelationId(String correlationId) {
        this.correlationId = correlationId;
    }
}

Each HTTP request gets its own RequestContext.


5. Session Scope

session scope creates one bean instance per HTTP session.

import org.springframework.stereotype.Component;
import org.springframework.web.context.annotation.SessionScope;

@Component
@SessionScope
public class ShoppingCart {

    private final List<String> items = new ArrayList<>();

    public void addItem(String item) {
        items.add(item);
    }

    public List<String> getItems() {
        return items;
    }
}

Each user session gets its own ShoppingCart.

This is useful for things like:

  • shopping carts
  • user preferences
  • wizard-style form state

6. Using Scope Constants

Instead of writing scope names as strings, you can use Spring constants.

import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

@Component
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class ReportBuilder {
}

For singleton:

import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;

@Service
@Scope(ConfigurableBeanFactory.SCOPE_SINGLETON)
public class UserService {
}

7. XML Configuration Example

If you use XML configuration, define the scope with the scope attribute.

Singleton

<bean id="service" class="com.example.DummyService" scope="singleton"/>

Since singleton is the default, this is also valid:

<bean id="service" class="com.example.DummyService"/>

Prototype

<bean id="service" class="com.example.DummyService" scope="prototype"/>

With singleton scope, repeated calls to getBean("service") return the same object.

With prototype scope, repeated calls to getBean("service") return different objects.


8. Lifecycle Difference

Singleton beans are fully managed by Spring, including destruction callbacks.

import jakarta.annotation.PostConstruct;
import jakarta.annotation.PreDestroy;
import org.springframework.stereotype.Service;

@Service
public class CacheService {

    @PostConstruct
    public void init() {
        System.out.println("Cache initialized");
    }

    @PreDestroy
    public void shutdown() {
        System.out.println("Cache shutting down");
    }
}

For singleton beans:

  • Spring creates the bean
  • Spring initializes it
  • Spring calls destruction callbacks when the context closes

For prototype beans:

  • Spring creates and initializes the bean
  • Spring does not manage the full destruction lifecycle after handing it out

So if a prototype bean holds resources, your application is responsible for cleanup.


9. Choosing the Right Scope

Use this as a practical guide:

Use case Recommended scope
Stateless service singleton
Repository/data access object singleton
Controller usually singleton
Stateful object created per use prototype
Request-specific data request
User-session data session

Best Practices

  1. Keep singleton beans stateless when possible.
  2. Do not store user-specific data in singleton services.
  3. Use prototype for objects that need independent state per use.
  4. Use ObjectProvider<T> when a singleton needs fresh prototype instances.
  5. Use @RequestScope for per-request web data.
  6. Use @SessionScope carefully, because session state consumes memory.
  7. Prefer annotation-based configuration in modern Spring applications.
  8. Use XML scope configuration only when working with XML-based Spring setup.

Bottom Line

You manage bean scope in Spring by declaring the scope on the bean:

@Component
@Scope("prototype")
public class MyBean {
}

or:

@Bean
@Scope("prototype")
public MyBean myBean() {
    return new MyBean();
}

If you do not specify a scope, Spring uses:

singleton

So in most applications, services, repositories, and controllers are singleton beans, while stateful per-use objects should be prototype, request, or session scoped depending on how long their state should live.