Understanding Spring Boot Controller Scope: Singleton vs Prototype and Thread Safety
This article explains why Spring MVC controllers are singleton by default, demonstrates the thread‑safety issues caused by non‑static member variables, shows how applying @Scope("prototype") changes behavior, and summarizes the five Spring bean scopes with practical recommendations.
By default, a Spring MVC @Controller is a singleton, so using non‑static member variables can lead to data inconsistency because the instance is shared across threads.
Example code demonstrates the problem:
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; a subsequent call to /testScope2 prints 2, showing that the same controller instance is reused and the state is shared, which is not thread‑safe.
Changing the controller to prototype scope resolves the issue:
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 /testScope and /testScope2 return 1 on each request, confirming that a new controller instance is created each time.
Key takeaways:
Do not define mutable member variables in a singleton controller.
If a member variable is required, annotate the controller with @Scope("prototype") to make it prototype‑scoped.
Alternatively, use ThreadLocal for thread‑confined data.
Spring bean scopes overview (five types):
singleton : one 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, managed by Spring in web applications.
session : a new instance for each HTTP session.
global session : a single instance for the entire web application, similar to the servlet application scope.
For further reading, a recommended Spring Boot tutorial is available at http://blog.didispace.com/spring-boot-learning-2x/ .
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.
Java Captain
Focused on Java technologies: SSM, the Spring ecosystem, microservices, MySQL, MyCat, clustering, distributed systems, middleware, Linux, networking, multithreading; occasionally covers DevOps tools like Jenkins, Nexus, Docker, ELK; shares practical tech insights and is dedicated to full‑stack Java development.
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.
