配置类中的@RefreshScope [英] @RefreshScope in Configuration class
问题描述
我有一个 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.
@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@Bean
s 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屋!