Backend Development 10 min read

Mastering Spring Bean Scopes: When to Use Singleton, Prototype, Request, Session, and More

This article explains Spring's bean scopes—including singleton, prototype, request, session, and application—detailing their lifecycles, appropriate use cases, and how to configure them with code examples, while also covering common pitfalls and proxy solutions for web environments.

Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
Mastering Spring Bean Scopes: When to Use Singleton, Prototype, Request, Session, and More

1. Introduction

Spring Scope Bean is a mechanism that defines the lifecycle and instantiation strategy of beans in the Spring container.

Spring provides several scopes such as singleton, prototype, request, session, and others, each suited to different scenarios.

Singleton : The default scope; only one instance exists in the container.

Prototype : A new instance is created each time the bean is requested.

Request : One instance per HTTP request.

Session : One instance per HTTP session.

Additional scopes like application and WebSocket are also available for specific needs.

Choosing the right scope can improve performance and resource utilization.

2. Scope Applications

2.1 Singleton

<code>@Bean
// No @Scope needed; default is singleton
@Scope(value = "singleton")
public Person person() {
    return new Person();
}</code>

Testing shows the same instance is returned each time.

<code>try (AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext()) {
    context.registerBean(Config.class);
    context.refresh();
    System.out.println(context.getBean(Person.class));
    System.out.println(context.getBean(Person.class));
}</code>
<code>com.pack.main.scope.ScopeMain5$Person@5e0e82ae - 1578009262
com.pack.main.scope.ScopeMain5$Person@5e0e82ae - 1578009262</code>

All calls return the same instance.

2.2 Prototype

<code>@Bean
@Scope(value = "prototype")
public Person person() {
    return new Person();
}</code>
<code>com.pack.main.scope.ScopeMain5$Person@fa4c865 - 262457445
com.pack.main.scope.ScopeMain5$Person@3bd82cf5 - 1004023029</code>

Each call creates a different object.

2.3 Request

In a Spring Boot web environment, request‑scoped beans must be used with a proxy or @RequestScope.

<code>@Component
@Scope(value = "request")
public class Person { }

@RestController
@RequestMapping("/scopes")
public class ScopeController {
    @Resource private Person person;
    @Resource private PersonService ps;
    @GetMapping("/request")
    public Person request() {
        System.out.println("ScopeController: " + person);
        ps.query();
        return person;
    }
}

@Service
public class PersonService {
    @Resource private Person person;
    public void query() {
        System.out.println("PersonService: " + person);
    }
}</code>

Without a proxy, the application throws an IllegalStateException because a request‑scoped bean is injected into a singleton.

Set proxy mode on @Scope

<code>@Component
@Scope(value = "request", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class Person { }</code>

Testing shows different instances per request but the same instance within a single request.

<code>ScopeController: com.pack.scopes.Person@106a9684 - 275420804
PersonService: com.pack.scopes.Person@106a9684 - 275420804
ScopeController: com.pack.scopes.Person@64396678 - 1681483384
PersonService: com.pack.scopes.Person@64396678 - 1681483384</code>

2.4 Session

<code>@Component
@Scope(value = "session", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class Person { }</code>

Repeated accesses in the same browser return the same instance; different browsers get different sessions.

<code>ScopeController: com.pack.scopes.Person@2b56038d - 727057293
PersonService: com.pack.scopes.Person@2b56038d - 727057293</code>

2.5 Application

<code>@Scope(value = "application", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class Person { }</code>

The bean lives for the entire application lifecycle, shared across all requests and sessions.

<code>ScopeController: com.pack.scopes.Person@6371b4b6 - 1668396214
PersonService: com.pack.scopes.Person@6371b4b6 - 1668396214</code>

3. Web Scope Internals

3.1 Registering Scopes

<code>public abstract class AbstractApplicationContext {
    public void refresh() {
        postProcessBeanFactory(beanFactory);
    }
}

public class ServletWebServerApplicationContext {
    protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
        registerWebApplicationScopes();
    }
    private void registerWebApplicationScopes() {
        WebApplicationContextUtils.registerWebApplicationScopes(getBeanFactory());
    }
}

public abstract class WebApplicationContextUtils {
    public static void registerWebApplicationScopes(ConfigurableListableBeanFactory beanFactory) {
        beanFactory.registerScope(WebApplicationContext.SCOPE_REQUEST, new RequestScope());
        beanFactory.registerScope(WebApplicationContext.SCOPE_SESSION, new SessionScope());
        // optional application scope registration
    }
}</code>

Each web scope has a corresponding Scope implementation (RequestScope, SessionScope, ServletContextScope).

3.2 Looking Up Web‑Scoped Beans

<code>public abstract class AbstractBeanFactory {
    protected <T> T doGetBean(...) {
        if (mbd.isSingleton()) {
            // retrieve from singleton cache
        } else if (mbd.isPrototype()) {
            // create new instance each time
        } else {
            String scopeName = mbd.getScope();
            Scope scope = this.scopes.get(scopeName);
            if (scope == null) {
                throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
            }
            Object scopedInstance = scope.get(beanName, () -> {
                beforePrototypeCreation(beanName);
                return createBean(beanName, mbd, args);
            });
        }
    }
}</code>

Summary: Spring bean scopes define bean lifecycles; selecting the appropriate scope optimizes performance and resource usage.

BackendJavaSpringdependency injectionBean Scope
Spring Full-Stack Practical Cases
Written by

Spring Full-Stack Practical Cases

Full-stack Java development with Vue 2/3 front-end suite; hands-on examples and source code analysis for Spring, Spring Boot 2/3, and Spring Cloud.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.