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

如何在单例Bean中刷新@RefreshScope Bean?BeanFactory.getBean无效

问题

运行时更新/刷新特定配置值时,已成功刷新配置(可通过actuator/env验证),但无法更新RefreshScope作用域下的配置Bean。调用刷新端点后,接口仍返回旧值,尝试调用refreshScope.refreshAll()、通过BeanFactory获取新实例均无效,仅直接从Environment获取属性有效,希望获取配置类的刷新后实例。

配置Bean代码:

@ConfigurationProperties(prefix = "refreshable")
@RefreshScope
public record RefreshableProperties(
        Optional<String> valueOne,
        Optional<Integer> valueTwo
) {
}

控制器代码:

@RestController
@RequiredArgsConstructor
public class MainController {

    private final BeanFactory beanFactory;

    private final ContextRefresher contextRefresher;

    private final RefreshScope refreshScope;

    @GetMapping("/current")
    public String getCurrent() {
        return loadCurrent().toString();
    }

    @GetMapping("/refresh")
    public String refresh() {
        contextRefresher.refresh();//此操作有效,actuator/env已返回刷新后的值
        refreshScope.refreshAll();
        return loadCurrent().toString(); // 返回旧值
    }

    private RefreshableProperties loadCurrent() {
        return beanFactory.getBean(RefreshableProperties.class);
    }

}
解决方案

问题核心是RefreshScope的代理机制和Bean获取方式不匹配,按以下方式调整即可:

  • 直接注入RefreshableProperties替代BeanFactory获取
    RefreshScope管理的Bean是代理对象,直接通过Spring依赖注入获取的代理实例,会在每次调用方法时自动检查缓存是否失效,若已失效则重新创建绑定最新配置的实例。修改控制器代码:

    @RestController
    @RequiredArgsConstructor
    public class MainController {
    
        private final ContextRefresher contextRefresher;
        private final RefreshScope refreshScope;
        // 直接注入RefreshableProperties
        private final RefreshableProperties refreshableProperties;
    
        @GetMapping("/current")
        public String getCurrent() {
            return refreshableProperties.toString();
        }
    
        @GetMapping("/refresh")
        public String refresh() {
            contextRefresher.refresh();
            refreshScope.refreshAll();
            // 此时调用refreshableProperties会自动拿到新实例
            return refreshableProperties.toString();
        }
    }
    
  • 若必须手动获取Bean,通过RefreshScope的get方法
    若场景限制必须手动获取,不能直接用BeanFactory.getBean(),而是要通过RefreshScope的API获取最新实例:

    private RefreshableProperties loadCurrent() {
        return (RefreshableProperties) refreshScope.get(
            () -> beanFactory.getBean(RefreshableProperties.class)
        );
    }
    
  • 核心逻辑说明
    RefreshScope会为Bean生成代理,调用refreshAll()时会清除该作用域内的Bean缓存。直接注入的代理Bean每次调用方法时会校验缓存状态,而BeanFactory.getBean()拿到的是旧代理实例,不会主动触发缓存校验和实例重建。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 05:33:22