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

Spring组件返回含前次运行数据的列表问题解决诉求

Spring Bean状态残留问题解决

问题场景

我有如下Spring组件,它自动装配了其他Bean,并通过getConfigurators(String Id)方法以列表形式返回这些组件:

@Component
public class Configuration{

    @Autowired
    private Config Config1;
    @Autowired
    private Config Config2;

    @Override
    public List<Config> getConfigurators(String Id) {
        return List.of(
                Config1,
                Config2);
       }
     }

首次运行应用时,getConfigurators(String Id)的结果完全正确,但后续调用时,返回的组件会带有首次运行时填充的配置值。我需要每次调用时,返回的组件都不携带之前的配置残留。

Config类的实现示例:

@Component
public class Config1 implements Config {
 final List errors = new ArrayList<>();
   @Override
    public List validate() {
        boolean isValid = // 自定义校验逻辑
        if (!isValid) {
            errors.add("Some error");
        }
        return errors;
    }
}

问题原因

Spring默认的Bean作用域是单例(Singleton),也就是说Config1和Config2在Spring容器中只会被创建一次。每次调用validate()方法时,都会往同一个errors列表中添加数据,导致之前的状态被保留下来,后续调用时就会带上历史数据。

解决方案

方案1:将Config Bean改为原型作用域

把Config1、Config2这类Bean的作用域改为原型(Prototype),这样每次从容器获取Bean时都会创建新的实例,自然不会有状态残留。

需要注意:直接用@Autowired注入原型Bean时,Spring只会在初始化依赖类时创建一次原型实例。因此需要用ObjectProvider来动态获取新实例。

修改后的代码如下:

Config1类修改

@Component
@Scope("prototype") // 或者使用ConfigurableBeanFactory.SCOPE_PROTOTYPE常量
public class Config1 implements Config {
    private final List<String> errors = new ArrayList<>();

    @Override
    public List<String> validate() {
        boolean isValid = // 你的校验逻辑
        if (!isValid) {
            errors.add("Some error");
        }
        return errors;
    }
}

Configuration类修改

@Component
public class Configuration{

    @Autowired
    private ObjectProvider<Config1> config1Provider;
    @Autowired
    private ObjectProvider<Config2> config2Provider;

    @Override
    public List<Config> getConfigurators(String Id) {
        return List.of(
                config1Provider.getObject(), // 每次调用都生成新实例
                config2Provider.getObject());
       }
     }

方案2:让Config类变为无状态

如果不需要在Config类中保留成员变量的状态,直接在validate()方法内部创建errors列表,这样即使是单例Bean,每次调用都会生成新的列表,不会有残留。

修改后的Config1类:

@Component
public class Config1 implements Config {

    @Override
    public List<String> validate() {
        List<String> errors = new ArrayList<>(); // 每次调用都新建列表
        boolean isValid = // 你的校验逻辑
        if (!isValid) {
            errors.add("Some error");
        }
        return errors;
    }
}

方案选择

  • 如果Config类需要保留一些初始化后的固定状态,但每次调用校验都要重置临时状态,优先选择原型作用域方案。
  • 如果Config类不需要任何持久化状态,推荐做成无状态单例,单例Bean的性能更好,也更符合Spring的设计习惯。

内容的提问来源于stack exchange,提问作者learningUser

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 14:35:11