SpringBoot并行调用同一Service出现数据重复问题及作用域咨询
问题场景
我有一个Controller调用ServiceA,代码如下:
@Autowired ServiceA serviceA; public @ResponseBody ResponseEntity<List<A>> getlistA(@RequestBody RequestA requestA) { List<RequestA> requestsListA = new ArrayList<>(); requestsListA.add(requestA); return new ResponseEntity<>(serviceA.getListA(requestsListA), HttpStatus.OK); }
ServiceA标注了@Service注解,代码如下:
@Scope public class ServiceA { … }
当并行发送两个请求时,发现第一个请求的数据出现在第二个请求的响应中:
- 串行执行两个请求时:
- 请求A的响应:object1, object2, object3
- 请求B的响应:object4, object5
- 并行执行两个请求时:
- 请求A的结果:object1, object2, object3, object4, object5
- 请求B的结果:object1, object2, object3, object4, object5
我的疑问:
- 标注@Service的类,Spring会在JVM中创建一个共享实例吗?
- 每个自动注入该服务的消费类会获取新实例吗?
- 是否可以强制每次调用服务时都创建新实例?
备注:并行调用时响应数据全部合并,看起来像是单例导致的。
问题解答
1. 标注@Service的类,Spring默认会创建共享的单例实例
是的,Spring中@Service(包括@Component、@Repository、@Controller)这类注解标注的Bean,默认作用域为单例(Singleton)——整个Spring容器内只会存在一个该类的实例,所有依赖注入的地方共享这一个实例。你代码里的@Scope未指定具体值,Spring会默认使用单例作用域,这就是并行请求数据串混的核心原因:ServiceA是单例,若它内部有存储请求相关数据的成员变量,多个并行请求会同时修改这些变量,导致数据混乱。
2. 不会,自动注入默认获取同一个单例实例
所有消费类(比如你的Controller)通过@Autowired注入的ServiceA,默认都是同一个单例实例,不会为每个消费类创建新实例。除非修改ServiceA的作用域,否则不管多少个类注入它,拿到的都是同一个对象。
3. 可以,通过修改Bean作用域实现
要让每次调用服务时创建新实例,可修改ServiceA的作用域:
- 请求作用域:Web环境下使用
@Scope("request")或@RequestScope,每个HTTP请求都会创建新的ServiceA实例,请求结束后实例被销毁,适合隔离每个请求的状态。 - 原型作用域:使用
@Scope("prototype")或@PrototypeScope,每次从Spring容器中获取Bean时都会创建新实例。但注意,若单例Controller通过@Autowired注入原型Bean,Controller只会在初始化时获取一次实例,后续调用仍用同一个。这种情况需结合ObjectFactory或ApplicationContext每次获取新实例,示例代码:
@Autowired private ObjectFactory<ServiceA> serviceAFactory; public ResponseEntity<List<A>> getlistA(@RequestBody RequestA requestA) { ServiceA serviceA = serviceAFactory.getObject(); // 每次调用获取新实例 // ... 后续业务逻辑 }
另外,当前并行数据串混的问题,本质是ServiceA内部存在线程不安全的成员变量(比如存储结果的集合)。即使不修改作用域,也可通过将这些变量改为方法局部变量解决——方法局部变量是线程私有的,不会被多个请求共享,这可能比修改作用域更简单。
内容的提问来源于stack exchange,提问作者james
相关产品推荐
相关产品推荐

