Spring Bean Scopes: 5 Types, Common Pitfalls and Concurrency Gotchas

The article explains the five Spring Bean scopes, clarifies that scope only controls instance count and not thread safety, and walks through real‑world concurrency bugs such as mutable singleton fields, prototype beans losing their prototype nature, and request‑scoped beans failing in async threads, offering concrete fixes and usage recommendations.

Java Tech Workshop
Java Tech Workshop
Java Tech Workshop
Spring Bean Scopes: 5 Types, Common Pitfalls and Concurrency Gotchas

1. Bean Scopes

Singleton

Explanation: One instance for the whole application, shared by all requests and threads.

Creation time: Eagerly created at application startup (non‑lazy), giving the best performance.

Typical usage: Controllers, Services, Mappers, Components are singleton by default.

Pitfall: The singleton itself is safe; problems arise when mutable member variables are added, which causes most concurrency data‑mixing bugs.

Prototype

Explanation: A new instance is created each time the bean is requested from the container.

Hidden facts:

Spring does not manage prototype bean destruction; the container only initializes the bean, so manual resource release is required.

Prototype beans are not stored in Spring’s first‑level cache, therefore circular‑dependency fallback logic is not triggered.

Use case: Store independent data that must not be shared across threads, such as temporary task context or export parameters.

Request

Explanation: One bean instance per HTTP request; the bean is destroyed when the request ends.

Example: A login request creates a request‑scoped bean, which is discarded after the response; the next request gets a fresh bean.

Limitations: Only usable in web projects; non‑web projects throw errors. The main thread can use it, but asynchronous sub‑threads cannot by default.

Session

Explanation: The same bean instance is shared across multiple requests from the same browser session; it is destroyed when the browser closes or the session expires.

Example: After a user logs in, several API calls within an hour share the same session bean, suitable for storing temporary nickname or avatar information.

Note: Do not store large data, as it can consume server memory and cause Tomcat session overflow.

Application

Difference from Singleton: Singleton is per IoC container; Application scope is a global singleton across the entire Tomcat service, equivalent to a ServletContext global variable.

Typical use: Global configuration or application‑wide cache; most business beans never need this scope.

2. Common Pitfalls

Controller member variable causing data mixing

Symptom: Occasionally a user sees another user's shipping address; occurs a few times per day with no log errors.

@RestController
public class UserController {
    // Wrong: mutable field in a singleton bean
    private String userName;

    @GetMapping("/info")
    public Result getUser(String name) {
        this.userName = name;
        return userService.getInfo(userName);
    }
}

Root cause: Controllers are singleton; concurrent Tomcat threads overwrite the shared userName field, leading to data mixing.

Fixes:

Remove all member variables; use method‑local variables (stack‑based, thread‑isolated, zero overhead).

Annotate the controller with @Scope("prototype") to create a new instance per request.

Avoid adding synchronized; it drastically reduces throughput and can cause avalanche failures under high concurrency.

Prototype bean injected into a singleton service loses prototype behavior

Symptom: A tool class annotated with @Scope("prototype") is injected into a singleton service; under concurrency all threads receive the same instance, causing data interference.

Explanation: The singleton service is instantiated once at startup; Spring injects a single prototype instance at that time, and subsequent method calls reuse that same object, so the prototype annotation becomes ineffective.

@Service
public class TaskService {
    // Lazy retrieval: get a new prototype each call
    @Autowired
    private ObjectProvider<TaskUtil> taskUtilProvider;

    public void run() {
        TaskUtil util = taskUtilProvider.getIfAvailable();
        // use util
    }
}

This approach avoids manual ApplicationContext lookup, works with all Spring versions, and is production‑ready.

@Async call with request‑scoped bean throws NoSuchBeanException

Symptom: The main thread can obtain request parameters, but an asynchronous thread throws NoSuchBeanException.

Root cause: The request context is stored in a ThreadLocal of the Tomcat main thread; Spring’s default thread pool does not copy this context to async threads.

Solution: Use a custom async thread pool that propagates the request attributes, e.g.:

RequestContextHolder.setRequestAttributes(
    RequestContextHolder.getRequestAttributes(), true);

3. Scope Selection Guidance

Singleton

Thread‑safety: Stateless safe; stateful unsafe

Lifecycle: Project start → shutdown

Advice: Default for 95% of beans; avoid mutable fields

Prototype

Thread‑safety: Naturally thread‑safe

Lifecycle: Created on demand; no fixed destroy time

Advice: Use sparingly; excessive objects cause GC pressure

Request

Thread‑safety: Naturally thread‑safe

Lifecycle: One HTTP request

Advice: Store temporary request parameters

Session

Thread‑safety: Single‑user safe, multi‑user isolated

Lifecycle: User session lifetime

Advice: Light‑weight login info; avoid large data

Application

Thread‑safety: Thread‑unsafe

Lifecycle: Tomcat start → stop

Advice: Global static config; rarely needed

All scope‑related bugs appear only under concurrent load; single‑thread local tests cannot reveal them, leading to high remediation cost when they surface in production.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaConcurrencySpringSingletonPrototypeBean Scope
Java Tech Workshop
Written by

Java Tech Workshop

Focused on Java backend technologies, sharing fundamentals, multithreading, JVM, the Spring ecosystem, microservices, distributed systems, high concurrency, source‑code analysis, and practical experience. Continuously delivers high‑quality original content, interview guides, and learning roadmaps to help Java developers progress from beginner to advanced, enhancing technical skills and core competitiveness.

0 followers
Reader feedback

How this landed with the community

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.