Why Spring Boot Controllers Are Singleton by Default and How to Avoid Thread Safety Issues
This article explains that Spring Boot controllers are singleton by default, why that makes them unsafe when using non‑static fields, demonstrates the problem with sample code, and provides practical solutions such as using prototype scope or ThreadLocal variables.
Spring MVC controllers are singleton by default, so defining non‑static member variables can cause data logic confusion and thread‑safety problems.
Below is a simple demonstration.
package com.riemann.springbootdemo.controller;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* @author riemann
* @date 2019/07/29 22:56
*/
@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 http://localhost:8080/testScope the output is 1; then accessing http://localhost:8080/testScope2 yields 2. The different values show the controller is not thread‑safe.
Adding @Scope("prototype") to make the controller prototype:
package com.riemann.springbootdemo.controller;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* @author riemann
* @date 2019/07/29 22:56
*/
@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 URLs return 1, confirming each request gets a new instance.
Conclusion: singleton controllers are unsafe because their fields are shared across requests.
Solution
Do not define member variables in a controller.
If a non‑static field is necessary, annotate the controller with @Scope("prototype") to use prototype scope.
Alternatively, use ThreadLocal variables inside the controller.
Additional Information
Spring bean scopes include:
singleton : a single instance per Spring container (eagerly created unless lazy‑init is used).
prototype : a new instance each time getBean is called; Spring does not manage the lifecycle after creation.
request : a new instance for each HTTP request in a web application.
session : a new instance for each HTTP session.
global session : a global web scope similar to the servlet application context.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Programmer DD
A tinkering programmer and author of "Spring Cloud Microservices in Action"
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
