为什么Spring Boot中Service类的变量在每次接口请求时会保留旧值?
问题核心原因
该现象是Spring Bean默认作用域的正常表现,你遗漏了Spring容器管理Bean的作用域规则:
- Spring中被
@Service、@Controller、@Component等注解标注的类,默认作用域是单例(singleton),也就是说整个Spring应用运行期间,容器只会为这个类创建唯一的一个实例,所有注入这个Bean的地方都会复用同一个实例。 - 你代码里的
counter是Service的实例成员变量,单例模式下所有请求调用的都是同一个Service实例的learnSpring方法,自然会共用同一个counter变量,值会一直累加不会重置。 - 补充小误区:你提到的"类变量"是被
static修饰的变量,你当前代码里的counter是普通实例变量,只是因为Service是单例才表现出跨请求共用的效果,如果Service是多实例的,每个实例会有独立的counter。
额外提醒:Spring里的
@Controller默认也是单例,所以不要在Controller里定义可变的成员变量,否则也会出现跨请求数据串用的问题。
实现每次请求计数器重置的方案
方案1:修改Service的作用域为请求域
给你的Service类上加@Scope("request")注解,这样Spring容器会为每一个HTTP请求创建一个独立的Service实例,每个实例的counter初始值都是0,就能满足每次请求counter从0开始计数的需求:
@Service @Scope("request") public class Myservice { private int counter; public void learnSpring() { System.out.println("counter : "+ counter); counter++; } }
注意:如果你的Service还被其他非请求链路的Bean注入使用,请求域的作用域可能会引发注入异常,需要结合实际业务场景判断是否适用。
方案2:将计数器改为方法内部局部变量
如果计数器只在learnSpring方法调用的单次流程中使用,直接把counter定义在方法内部即可,每次调用方法都会初始化新的局部变量,不需要修改Bean作用域:
@Service public class Myservice { public void learnSpring() { int counter = 0; System.out.println("counter : "+ counter); counter++; // 后续单次请求内的逻辑继续使用counter即可 } }
方案3:保留单例Service同时隔离不同请求的计数器
可以用ThreadLocal存储计数器,利用Web服务每个请求对应独立线程的特性实现隔离,使用完注意清理避免内存泄漏:
@Service public class Myservice { private ThreadLocal<Integer> counterThreadLocal = ThreadLocal.withInitial(() -> 0); public void learnSpring() { Integer counter = counterThreadLocal.get(); System.out.println("counter : "+ counter); counterThreadLocal.set(counter + 1); // 单次请求逻辑结束后调用 counterThreadLocal.remove(); 清理 } }
内容的提问来源于stack exchange,提问作者Stalwart
相关产品推荐
相关产品推荐

