配置类中的@RefreshScope
Posted
技术标签:
【中文标题】配置类中的@RefreshScope【英文标题】:@RefreshScope in Configuration class 【发布时间】:2019-11-11 22:58:36 【问题描述】:我有一个 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 注释配置类时(意味着在类级别),如果在此类中声明的 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
根据 Spring doc,bean 应该通过在配置类级别注释 @RefreshScope 来刷新。无需为配置类的每个 bean 声明指定 @RefreshScope。我错过了什么吗?
顺便说一句,我通过在 bean 声明中放置断点来检查 bean 是否刷新。
第二个问题:我想我应该只有一个代理 bean 而不是我们在第二种情况下看到的两个 bean?
【问题讨论】:
您将拥有 2 个 bean 实例、1 个代理和 1 个实际实例。代理将在刷新后继续存在,并将委托给新创建的实际实例。将@RefreshScope
放在配置上确实会刷新配置,但不会刷新它创建的bean。您需要明确定义要刷新的 bean。这可以通过将所需的类注释为@RefreshScope
或将@Bean
方法注释为@RefreshScope
来完成。
【参考方案1】:
您的理解有点偏离,所有这些都在文档中说明。
来自javadoc 的@RefreshScope
。
实现涉及为范围内的每个 bean 创建一个代理,
因此您将获得 2 个 bean 实例。 1 个代理,它将实际包装 bean 的完整实例。刷新时,代理将继续存在,实际实例将被替换。
来自Spring Cloud Reference Guide:
@RefreshScope
(技术上)在@Configuration
类上工作,但它可能会导致令人惊讶的行为。例如,这并不意味着该类中定义的所有@Bean
s 本身都在@RefreshScope
中。具体来说,任何依赖于这些 bean 的东西都不能依赖它们在启动刷新时被更新,除非它本身在@RefreshScope
中。在这种情况下,它会在刷新时重建,并重新注入其依赖项。此时,它们会从刷新后的@Configuration
重新初始化。
因此,虽然在技术上可能使用对这些 bean 的引用但可能不会刷新,除非它们也被标记为 @RefreshScope
。
简而言之,解决方案是通过将类注释为@RefreshScope
或@Bean
方法来显式标记需要在@RefreshScope
中的bean。
【讨论】:
以上是关于配置类中的@RefreshScope的主要内容,如果未能解决你的问题,请参考以下文章
配置中心@ConfigurationProperties+@RefreshScope 动态配置
解决 @RefreshScope 导致定时任务注解 @Scheduled 失效
解决 @RefreshScope 导致定时任务注解 @Scheduled 失效
解决 @RefreshScope 导致定时任务注解 @Scheduled 失效