配置类中的@RefreshScope [英] @RefreshScope in Configuration class

查看:37
本文介绍了配置类中的@RefreshScope的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have a spring boot application. I am using Spring Cloud Config to externalize properties - through Git. Everything works fine. I would like the beans to be refreshed when I issue the actuator refresh endpoint. Beans are refreshed eagerly as expected by doing the following:

@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 声明中没有自己 @RefreshScope,则不会刷新在此类中声明的 bean.

The only thing not working as expected is when I annotate a Configuration class with @refreshScope (meaning at the class level), beans declared in this class are not refreshed if they don't have themselves @RefreshScope in the bean declaration.

这里的 bean 没有刷新:

Here the bean is not refreshed:

@Configuration
@RefreshScope
public class DraftsClientConfiguration {

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

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

Here is the log from my RefreshListener class: We can see that in this case, there is only one bean that is not proxied.

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

但是这里的 bean 被刷新了:

But here the bean is refreshed:

@Configuration
public class DraftsClientConfiguration {

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

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

In this second case, we have two beans (should it be the case?), one proxied and one not proxied.

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

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

According to Spring doc, beans should be refreshed by annotating @RefreshScope at the configuration class level. There is no need to specify @RefreshScope for every bean declaration of the configuration class. Am I missing something?

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

By the way, I am checking if the bean is refreshed or not by putting a breakpoint in the bean declaration.

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

Second question: I guess I should have only one proxied bean and not two beans as we can see in the second case?

推荐答案

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

Your understanding is a bit off and all of that is stated in the documentation.

来自 javadoc.

From the javadoc of @RefreshScope.

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

The implementation involves creating a proxy for every bean in the scope,

因此您将获得 2 个 bean 实例.1 个代理,它将实际包装 bean 的完整实例.刷新时,代理将继续运行并替换实际实例.

So you will get 2 instances of the bean. 1 Proxy which will actually wrap an full instance of the bean. When being refreshed, the proxy will survice and the actual instance will be replaced.

来自 Spring Cloud 参考指南:

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

@RefreshScope works (technically) on an @Configuration class, but it might lead to surprising behavior. For example, it does not mean that all the @Beans defined in that class are themselves in @RefreshScope. Specifically, anything that depends on those beans cannot rely on them being updated when a refresh is initiated, unless it is itself in @RefreshScope. In that case, it is rebuilt on a refresh and its dependencies are re-injected. At that point, they are re-initialized from the refreshed @Configuration).

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

So while it might be technically possible using references to those beans might not refresh, unless those are also marked as @RefreshScope.

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

In short the solution is to explicitly mark which beans need to be in @RefreshScope by either annotating the class as @RefreshScope or the @Bean method.

这篇关于配置类中的@RefreshScope的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆