Spring Cloud @RefreshScope 原理是什么?
要清楚RefreshScope,先要了解Scope
Scope(org.springframework.beans.factory.config.Scope)是Spring 2.0开始就有的核心的概念
RefreshScope(org.springframework.cloud.context.scope.refresh)是spring cloud提供的一种特殊的scope实现,用来实现配置、实例热加载。
Scope -> GenericScope -> RefreshScope
Scope与ApplicationContext生命周期
AbstractBeanFactory#doGetBean创建Bean实例
protected <T> T doGetBean(...){final RootBeanDefinition mbd = ...if (mbd.isSingleton()) {...} else if (mbd.isPrototype())...} else {String scopeName = mbd.getScope();final Scope scope = this.scopes.get(scopeName);Object scopedInstance = scope.get(beanName, new ObjectFactory<Object>() {...});...}...
}
Singleton和Prototype是硬编码的,并不是Scope子类。
Scope实际上是自定义扩展的接口,Scope Bean实例交由Scope自己创建,例如SessionScope是从Session中获取实例的,ThreadScope是从ThreadLocal中获取的,而RefreshScope是在内建缓存中获取的。
@Scope 对象的实例化
@RefreshScope 是scopeName="refresh"的 @Scope
...
@Scope("refresh")
public @interface RefreshScope {...
}
@Scope 的注册 AnnotatedBeanDefinitionReader#registerBean
public void registerBean(...){
...
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);abd.setScope(scopeMetadata.getScopeName());...definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
}
读取@Scope元数据, AnnotationScopeMetadataResolver#resolveScopeMetadata
public ScopeMetadata resolveScopeMetadata(BeanDefinition definition) {AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(annDef.getMetadata(), Scope.class);if (attributes != null) {metadata.setScopeName(attributes.getString("value"));ScopedProxyMode proxyMode = attributes.getEnum("proxyMode");if (proxyMode == null || proxyMode == ScopedProxyMode.DEFAULT) {proxyMode = this.defaultProxyMode;}metadata.setScopedProxyMode(proxyMode);}
}
Scope实例对象通过ScopedProxyFactoryBean创建,其中通过AOP使其实现ScopedObject接口,这里不再展开。
说RefreshScope是如何实现配置和实例刷新的
RefreshScope注册
RefreshAutoConfiguration#RefreshScopeConfiguration
@Component
@ConditionalOnMissingBean(RefreshScope.class)
protected static class RefreshScopeConfiguration implements BeanDefinitionRegistryPostProcessor{
...registry.registerBeanDefinition("refreshScope",BeanDefinitionBuilder.genericBeanDefinition(RefreshScope.class).setRole(BeanDefinition.ROLE_INFRASTRUCTURE).getBeanDefinition());
...
}
RefreshScope extends GenericScope, 大部分逻辑在 GenericScope 中。
GenericScope#postProcessBeanFactory 中向AbstractBeanFactory注册自己
public class GenericScope implements Scope, BeanFactoryPostProcessor...{@Overridepublic void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)throws BeansException {beanFactory.registerScope(this.name/*refresh*/, this/*RefreshScope*/);...}
}
RefreshScope 刷新过程
入口在ContextRefresher#refresh
refresh() {Map<String, Object> before = ①extract(this.context.getEnvironment().getPropertySources());②addConfigFilesToEnvironment();Set<String> keys = ④changes(before,③extract(this.context.getEnvironment().getPropertySources())).keySet();this.context.⑤publishEvent(new EnvironmentChangeEvent(keys));this.scope.⑥refreshAll();}
①提取标准参数(SYSTEM,JNDI,SERVLET)之外所有参数变量
②把原来的Environment里的参数放到一个新建的Spring Context容器下重新加载,完事之后关闭新容器
③提起更新过的参数(排除标准参数)
④比较出变更项
⑤发布环境变更事件,接收:EnvironmentChangeListener/LoggingRebinder
⑥RefreshScope用新的环境参数重新生成Bean,重新生成的过程很简单,清除refreshscope缓存幷销毁Bean,下次就会重新从BeanFactory获取一个新的实例(该实例使用新的配置)
RefreshScope#refreshAll
public void refreshAll() {<b>super.destroy();</b>this.context.publishEvent(new RefreshScopeRefreshedEvent());
}
GenericScope#destroy
public void destroy() {...Collection<BeanLifecycleWrapper> wrappers = <b>this.cache.clear()</b>;for (BeanLifecycleWrapper wrapper : wrappers) {<b>wrapper.destroy();</b>}
}
Spring Cloud Bus 如何触发 Refresh
BusAutoConfiguration#BusRefreshConfiguration 发布一个RefreshBusEndpoint
@Configuration
@ConditionalOnClass({ Endpoint.class, RefreshScope.class })
protected static class BusRefreshConfiguration {@Configuration@ConditionalOnBean(ContextRefresher.class)@ConditionalOnProperty(value = "endpoints.spring.cloud.bus.refresh.enabled", matchIfMissing = true)protected static class BusRefreshEndpointConfiguration {@Beanpublic RefreshBusEndpoint refreshBusEndpoint(ApplicationContext context,BusProperties bus) {return new RefreshBusEndpoint(context, bus.getId());}}
}
RefreshBusEndpoint 会从http端口触发广播RefreshRemoteApplicationEvent事件
@Endpoint(id = "bus-refresh")
public class RefreshBusEndpoint extends AbstractBusEndpoint {public void busRefresh() {publish(new RefreshRemoteApplicationEvent(this, getInstanceId(), null));}
}
BusAutoConfiguration#refreshListener 负责接收事件(所有配置bus的节点)
@Bean
@ConditionalOnProperty(value = "spring.cloud.bus.refresh.enabled", matchIfMissing = true)
@ConditionalOnBean(ContextRefresher.class)
public RefreshListener refreshListener(ContextRefresher contextRefresher) {return new RefreshListener(contextRefresher);
}
RefreshListener#onApplicationEvent 触发 ContextRefresher
public void onApplicationEvent(RefreshRemoteApplicationEvent event) {Set<String> keys = contextRefresher.refresh();
}
大部分需要更新的服务需要打上@RefreshScope, EurekaClient是如何配置更新的
EurekaClientAutoConfiguration#RefreshableEurekaClientConfiguration
@Configuration
@ConditionalOnRefreshScope
protected static class RefreshableEurekaClientConfiguration{@Bean@RefreshScopepublic EurekaClient eurekaClient(...) {return new CloudEurekaClient(manager, config, this.optionalArgs,this.context);}@Bean@RefreshScopepublic ApplicationInfoManager eurekaApplicationInfoManager(...) {...return new ApplicationInfoManager(config, instanceInfo);}}
作者:黄大海
https://www.jianshu.com/p/188013dd3d02
Spring Cloud @RefreshScope 原理是什么?相关推荐
- Spring Cloud底层原理(转载 石杉的架构笔记)
拜托!面试请不要再问我Spring Cloud底层原理 原创: 中华石杉 石杉的架构笔记 目录 一.业务场景介绍 二.Spring Cloud核心组件:Eureka 三.Spring Cloud核心组 ...
- Spring Cloud GateWay 原理
Spring Cloud GateWay 原理 一.概述 在微服务架构中,每个服务都是一个可以独立开发和运行的组件,而一个完整的微服务架构由一系列独立运行的微服务组成.其中每个服务都只会完成特定领域的 ...
- Spring Cloud Feign原理
Spring Cloud Feign原理 Feign运行过程 重试机制 服务降级 负载均衡 隔舱原理 Feign运行过程 通过主类上的EnableFeignClients 注解开启FeignClien ...
- Spring Cloud底层原理以及项目实战分析
一.业务场景介绍 二.Spring Cloud核心组件------------------------------------------------------------------------- ...
- 面试官:说说Spring Cloud底层原理?
点击上方"蓝字", 右上角选择"设为星标" 周一至周五上午11:45!精品文章准时送上! 本文转载自公众号:石杉的架构笔记 目录 一.业务场景介绍 二.Spri ...
- 面试请不要再问我Spring Cloud底层原理
目录 一.业务场景介绍 二.Spring Cloud核心组件:Eureka 三.Spring Cloud核心组件:Feign 四.Spring Cloud核心组件:Ribbon 五.Spring Cl ...
- 第二十一期:拜托!面试不要再问我Spring Cloud底层原理
毫无疑问,Spring Cloud 是目前微服务架构领域的翘楚,无数的书籍博客都在讲解这个技术. 不过大多数讲解还停留在对 Spring Cloud 功能使用的层面,其底层的很多原理,很多人可能并不知 ...
- 拜托!面试请不要再问我 Spring Cloud 底层原理 ...
前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家.点击跳转到教程. >出处: >https://www.fangzhipeng.com > 本文出自 ...
- spring cloud zuul 原理简介和使用
一 spring cloud zuul 简介 Spring Cloud Zuul 是 Spring Cloud Netflix 子项目的核心组件之一,可以作为微服务架构中的 API 网关使用,支持动态 ...
最新文章
- 软件测试培训分享:如何划分bug的严重级别
- 半折预售:新书-R语言数据可视化之美|ggplot2作者推荐
- AS3与lua之间的交互
- 《算法设计编程实验:大学程序设计课程与竞赛训练教材》——2.3 构造法模拟的实验范例...
- 20165232 缓冲区溢出漏洞实验
- [你必须知道的.NET] 第一回:恩怨情仇:is和as
- Maven配置项目依赖使用本地仓库的方法汇总
- [Effective C++读书笔记]003_条款03_尽可能使用const
- Z-BlogPHP导航主题模版源码 绿色完美版
- Ibatis2.0使用说明(二)——配置篇
- 内置对象 API Math对象、Data对象、Array对象、String对象
- Android基础入门教程——4.3.2 BroadcastReceiver庖丁解牛
- seaweedfs java_seaweedfs-java-client
- JVM?干就完了!(一) - hello world
- 左神进阶班-KMP算法
- I'm coming now.
- 概率计算机在线,高斯正态分布(概率)计算公式与在线计算器_三贝计算网_23bei.com...
- 秋招总结帖,还愿牛客
- Debian 11 修改 DNS 服务器
- mathematica使用笔记