配置类中的@RefreshScope

时间:2019-07-01 09:23:02

标签: java spring spring-boot spring-cloud-config

我有一个Spring Boot应用程序。我正在使用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
    }
}

唯一无法正常工作的是,当我使用@refreshScope(在类级别)对Configuration类进行注释时,如果此类声明的bean在bean声明中没有@RefreshScope,则不会刷新它们。

此处未刷新bean:

@Configuration
@RefreshScope
public class DraftsClientConfiguration {

    @Bean
    MyBean aBean() {
        return new MyBean();
    }
}

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

RefreshListener - Regular Bean: Bean name: draftsServiceClient - Bean class: class com.citi.qi.athena.drafts.DraftsServiceClient

但是这里的bean被刷新了:

@Configuration
public class DraftsClientConfiguration {

    @RefreshScope
    @Bean
    MyBean aBean() {
        return new MyBean();
    }
}

在第二种情况下,我们有两个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

我正在通过在bean声明中放置一个断点来检查是否刷新了bean。

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

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

第二个问题:我想我应该只有一个代理豆,而在第二种情况下不能看到两个豆?

1 个答案:

答案 0 :(得分:2)

您的理解有些偏离,所有这些都在文档中进行了说明。

来自@RefreshScope的{​​{3}}。

  

该实现涉及为作用域中的每个bean创建一个代理

因此,您将获得2个Bean实例。 1个代理,它实际上将包装Bean的完整实例。刷新后,代理将提供服务并替换实际实例。

来自javadoc

  

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

因此,尽管从技术上来说,使用对那些Bean的引用可能不会刷新,除非它们也被标记为@RefreshScope

简而言之,解决方案是通过将类注释为@RefreshScope@RefreshScope方法来显式标记哪些豆需要位于@Bean中。