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
相关产品推荐
相关产品推荐

