Backend Development 4 min read

Spring Controller Scope: Singleton vs Prototype and Concurrency Safety

The article explains that Spring MVC controllers are singleton by default, which makes mutable instance fields unsafe for concurrent requests, demonstrates the issue with sample code, and shows how applying @Scope("prototype") or using ThreadLocal resolves the thread‑safety problem.

Architect's Guide
Architect's Guide
Architect's Guide
Spring Controller Scope: Singleton vs Prototype and Concurrency Safety

In Spring MVC, a @Controller bean is singleton by default, meaning a single instance handles all requests and any mutable instance fields are shared across threads, leading to concurrency hazards.

Example code illustrates a controller with an int num field that is incremented in two request‑mapping methods:

@Controller public class ScopeTestController { private int num = 0; @RequestMapping("/testScope") public void testScope() { System.out.println(++num); } @RequestMapping("/testScope2") public void testScope2() { System.out.println(++num); } }

When accessing /testScope the output is 1; a subsequent call to /testScope2 yields 2, demonstrating that the same controller instance is reused and the field is not thread‑safe.

Adding @Scope("prototype") changes the bean to prototype scope, creating a new controller instance for each request:

@Controller @Scope("prototype") public class ScopeTestController { private int num = 0; @RequestMapping("/testScope") public void testScope() { System.out.println(++num); } @RequestMapping("/testScope2") public void testScope2() { System.out.println(++num); } }

Now both /testScope and /testScope2 return 1, confirming that each request gets its own instance and the field is no longer shared.

Recommended solutions are: (1) avoid defining mutable member variables in controllers; (2) if a variable is necessary, declare the controller with prototype scope using @Scope("prototype") ; (3) alternatively, store per‑thread data with ThreadLocal .

Spring bean scopes include singleton, prototype, request, session, and global session, each providing different lifecycle and visibility characteristics.

JavaconcurrencySpringControllersingletonPrototype
Architect's Guide
Written by

Architect's Guide

Dedicated to sharing programmer-architect skills—Java backend, system, microservice, and distributed architectures—to help you become a senior architect.

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.