我有一个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是否被刷新。
第二个问题:我想我应该只有一个代理豆,而在第二种情况下不能看到两个豆?
答案 0 :(得分:2)
您的理解有些偏离,所有这些都在文档中进行了说明。
来自@RefreshScope
的{{3}}。
该实现涉及为作用域中的每个bean创建一个代理
因此,您将获得2个Bean实例。 1个代理,它实际上将包装Bean的完整实例。刷新后,代理将提供服务并替换实际实例。
来自javadoc:
@RefreshScope
(在技术上)可用于@Configuration
类,但是它可能导致令人惊讶的行为。例如,这并不意味着该类中定义的所有@Bean
本身都在@RefreshScope
中。具体来说,除非刷新本身在@RefreshScope
中,否则所有依赖于这些bean的东西都不能依赖于刷新启动时对其进行更新。在这种情况下,将在刷新时重建它,并重新注入其依赖项。此时,它们将从刷新的@Configuration
开始重新初始化。
因此,尽管从技术上来说,使用对那些Bean的引用可能不会刷新,除非它们也被标记为@RefreshScope
。
简而言之,解决方案是通过将类注释为@RefreshScope
或@RefreshScope
方法来显式标记哪些豆需要位于@Bean
中。