配置类中的@RefreshScope

Myk*_*eul 9 java configuration spring spring-boot spring-cloud-config

我有一个弹簧启动应用程序。我正在使用 Spring Cloud Config 来外部化属性 - 通过 Git。一切正常。我希望在发出执行器刷新端点时刷新 bean。通过执行以下操作,Bean 会按预期快速刷新:

@EventListener
public void onRefreshScopeRefreshed(final RefreshScopeRefreshedEvent event) {
    logger.info("Received Refresh event. Refreshing all beans...");
    for (String beanName : applicationContext.getBeanDefinitionNames()) {
        Class<?> beanClass = applicationContext.getBean(beanName).getClass();
        if(beanClass.getName().contains("SpringCGLIB")) {
            logger.info("Proxied bean: bean name: " + beanName + " - Bean class: " + applicationContext.getBean(beanName).getClass());
        } else {
            logger.info("Regular Bean: Bean name: " + beanName + " - Bean class: " + applicationContext.getBean(beanName).getClass());
        }
        applicationContext.getBean(beanName).getClass(); // to cause refresh eagerly
    }
}
Run Code Online (Sandbox Code Playgroud)

唯一没有按预期工作的事情是,当我使用 @refreshScope 注释 Configuration 类(意味着在类级别)时,如果在 bean 声明中没有自己 @RefreshScope,则不会刷新在此类中声明的 bean。

这里的 bean 没有刷新:

@Configuration
@RefreshScope
public class DraftsClientConfiguration {

    @Bean
    MyBean aBean() {
        return new MyBean();
    }
}
Run Code Online (Sandbox Code Playgroud)

这是我的 RefreshListener 类的日志: 我们可以看到,在这种情况下,只有一个 bean 没有被代理。

RefreshListener - Regular Bean: Bean name: draftsServiceClient - Bean class: class com.citi.qi.athena.drafts.DraftsServiceClient
Run Code Online (Sandbox Code Playgroud)

但是这里 bean 被刷新了:

@Configuration
public class DraftsClientConfiguration {

    @RefreshScope
    @Bean
    MyBean aBean() {
        return new MyBean();
    }
}
Run Code Online (Sandbox Code Playgroud)

在第二种情况下,我们有两个 bean(应该是这样吗?),一个被代理,一个没有被代理。

RefreshListener - Regular Bean: Bean name: scopedTarget.draftsServiceClient - Bean class: class com.citi.qi.athena.drafts.DraftsServiceClient
RefreshListener - Proxied bean: bean name: draftsServiceClient - Bean class: class com.citi.qi.athena.drafts.DraftsServiceClient$$EnhancerBySpringCGLIB$$bbfd1caf
Run Code Online (Sandbox Code Playgroud)

根据 Spring 文档,应该通过在配置类级别注释 @RefreshScope 来刷新 bean。无需为配置类的每个 bean 声明指定 @RefreshScope。我错过了什么吗?

顺便说一下,我正在通过在 bean 声明中放置一个断点来检查 bean 是否刷新。

第二个问题:我想我应该只有一个代理 bean 而不是我们在第二种情况下看到的两个 bean?

M. *_*num 14

您的理解有点偏差,所有这些都在文档中说明。

的Javadoc@RefreshScope

实现涉及为范围内的每个 bean 创建一个代理,

所以你会得到 2 个 bean 实例。1 个代理,它将实际包装 bean 的完整实例。刷新时,代理将继续运行并替换实际实例。

来自Spring Cloud 参考指南

@RefreshScope在一个@Configuration类上工作(技术上),但它可能会导致令人惊讶的行为。例如,这并不意味着@Bean该类中定义的所有s 本身都在@RefreshScope. 具体来说,任何依赖于这些 bean 的东西都不能依赖于在启动刷新时更新它们,除非它本身在@RefreshScope. 在这种情况下,它会在刷新时重建,并重新注入其依赖项。那时,它们从刷新的@Configuration)中重新初始化。

因此,虽然在技术上可能使用对这些 bean 的引用可能不会刷新,除非它们也被标记为 @RefreshScope.

简而言之,解决方案是@RefreshScope通过将类注释为@RefreshScope@Bean方法来明确标记哪些 bean 需要在其中。