You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为什么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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.01 22:09:03