配置中的@RefreshScope class
@RefreshScope in Configuration class
我有一个 spring 启动应用程序。我正在使用 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(意思是在class级别)注释配置class时,在这个class中声明的bean没有刷新如果他们在 bean 声明中没有自己的@RefreshScope。
这里的bean没有刷新:
@Configuration
@RefreshScope
public class DraftsClientConfiguration {
@Bean
MyBean aBean() {
return new MyBean();
}
}
这是来自我的 RefreshListener class 的日志:
我们可以看到在这种情况下,只有一个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
根据 Spring 文档,bean 应该通过在配置 class 级别注释 @RefreshScope 来刷新。无需为配置的每个 bean 声明指定 @RefreshScope class。我错过了什么吗?
顺便说一句,我通过在 bean 声明中放置一个断点来检查 bean 是否被刷新。
第二个问题:我想我应该只有一个代理 bean 而不是我们在第二种情况下看到的两个 bean?
你的理解有点偏差,文档里都有说明。
来自 @RefreshScope
的 javadoc。
The implementation involves creating a proxy for every bean in the scope,
因此您将获得 2 个 bean 实例。 1 实际包装 bean 的完整实例的代理。刷新时,代理将继续服务并替换实际实例。
来自Spring Cloud Reference Guide:
@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
。
简而言之,解决方案是通过将 class 注释为 @RefreshScope
或 @Bean
方法来显式标记哪些 bean 需要在 @RefreshScope
中。
我有一个 spring 启动应用程序。我正在使用 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(意思是在class级别)注释配置class时,在这个class中声明的bean没有刷新如果他们在 bean 声明中没有自己的@RefreshScope。
这里的bean没有刷新:
@Configuration
@RefreshScope
public class DraftsClientConfiguration {
@Bean
MyBean aBean() {
return new MyBean();
}
}
这是来自我的 RefreshListener class 的日志: 我们可以看到在这种情况下,只有一个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
根据 Spring 文档,bean 应该通过在配置 class 级别注释 @RefreshScope 来刷新。无需为配置的每个 bean 声明指定 @RefreshScope class。我错过了什么吗?
顺便说一句,我通过在 bean 声明中放置一个断点来检查 bean 是否被刷新。
第二个问题:我想我应该只有一个代理 bean 而不是我们在第二种情况下看到的两个 bean?
你的理解有点偏差,文档里都有说明。
来自 @RefreshScope
的 javadoc。
The implementation involves creating a proxy for every bean in the scope,
因此您将获得 2 个 bean 实例。 1 实际包装 bean 的完整实例的代理。刷新时,代理将继续服务并替换实际实例。
来自Spring Cloud Reference Guide:
@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
。
简而言之,解决方案是通过将 class 注释为 @RefreshScope
或 @Bean
方法来显式标记哪些 bean 需要在 @RefreshScope
中。