前言
- SpringMVC 和 SpringBoot 的线程安全性与框架的设计模式及开发者的代码实现密切相关。
关键结论
- Controller 的单例模式
- SpringMVC 和 SpringBoot 的 Controller 默认均为单例,这种设计优化了性能(避免频繁创建对象)。
- 但若在 Controller 中定义非静态成员变量(如 private int count),会导致多线程竞争修改数据,破坏线程安全。
- 线程安全的条件
- 安全场景:若 Controller 无成员变量,或仅依赖无状态的 Bean(如 Service 层),则线程安全。
- 不安全场景:若 Controller 包含可修改的成员变量(如计数器、缓存对象),需通过 @Scope(“prototype”) 设为多例,或使用 ThreadLocal、Atomic 类型等线程安全工具。
- SpringBoot 的特殊性:SpringBoot 本身不改变 SpringMVC 的线程安全规则,但通过以下方式简化安全开发:
- 依赖注入无状态的 Bean:Service 层默认单例且无状态(依赖注入的 Bean 通常无成员变量),天然线程安全。
- 自动配置约束:减少开发者误用共享资源的可能性。
代码示例
@Controller
public class UnsafeController {
private int count = 0;
@RequestMapping("/count")
@ResponseBody
public String count() {
return "Count: " + (++count);
}
}
@Controller
public class SafeController {
@Autowired
private StatelessService service;
@RequestMapping("/data")
@ResponseBody
public String getData() {
return service.fetchData();
}
}
解决方案
- 保持无状态:Controller 中只操作方法参数、局部变量和线程安全的依赖对象。
- 多例模式:通过 @Scope(“prototype”) 为 Controller 启用多例(牺牲部分性能)。
- 线程隔离工具:使用 ThreadLocal 或 AtomicInteger 等处理共享资源。
- 依赖注入替代成员变量:将共享资源封装为无状态的 Bean(如 Service 层)。
总结
