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...{
@Override
public 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 {
@Bean
public 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
@RefreshScope
public EurekaClient eurekaClient(...) {
return new CloudEurekaClient(manager, config, this.optionalArgs,
this.context);
}
@Bean
@RefreshScope
public ApplicationInfoManager eurekaApplicationInfoManager(...) {
...
return new ApplicationInfoManager(config, instanceInfo);
}
}
Spring Cloud @RefreshScope 原理是什么?的更多相关文章
- 拜托!面试请不要再问我Spring Cloud底层原理[z]
[z]https://juejin.im/post/5be13b83f265da6116393fc7 拜托!面试请不要再问我Spring Cloud底层原理 欢迎关注微信公众号:石杉的架构笔记(id: ...
- Spring Cloud底层原理(转载 石杉的架构笔记)
拜托!面试请不要再问我Spring Cloud底层原理 原创: 中华石杉 石杉的架构笔记 目录 一.业务场景介绍 二.Spring Cloud核心组件:Eureka 三.Spring Cloud核 ...
- [转帖]Spring Cloud底层原理
拜托!面试不要再问我Spring Cloud底层原理 https://mp.weixin.qq.com/s/ZH-3JK90mhnJPfdsYH2yDA 毫无疑问,Spring Cloud 是目前微服 ...
- 拜托!面试请不要再问我Spring Cloud底层原理
概述 毫无疑问,Spring Cloud是目前微服务架构领域的翘楚,无数的书籍博客都在讲解这个技术.不过大多数讲解还停留在对Spring Cloud功能使用的层面,其底层的很多原理,很多人可能并不知晓 ...
- spring cloud bus原理总结
1.spring cloud bus spring cloud是按照spring的配置对一系列微服务框架的集成,spring cloud bus是其中一个微服务框架,用于实现微服务之间的通信. spr ...
- 【转载】Spring Cloud底层原理
概述 毫无疑问,Spring Cloud是目前微服务架构领域的翘楚,无数的书籍博客都在讲解这个技术.不过大多数讲解还停留在对Spring Cloud功能使用的层面,其底层的很多原理,很多人可能并不知晓 ...
- Spring Cloud底层原理
目录 一.业务场景介绍 二.Spring Cloud核心组件:Eureka 三.Spring Cloud核心组件:Feign 四.Spring Cloud核心组件:Ribbon 五.Spring Cl ...
- Spring Cloud Gateway原理
1.使用 compile 'org.springframework.cloud:spring-cloud-starter-gateway' 2.包结构 actuate中定义了一个叫GatewayCon ...
- Spring Cloud底层原理解析
概述 毫无疑问,Spring Cloud是目前微服务架构领域的翘楚,无数的书籍博客都在讲解这个技术.不过大多数讲解还停留在对Spring Cloud功能使用的层面,其底层的很多原理,很多人可能并不知晓 ...
随机推荐
- nginx报错111: Connection refused
最近遇到了nginx疯狂抛错,access.log一天一共5W多条,但error.log中有大概9K多条,基本都是111: Connection refused,这到底是为什么呢? 从日志看起 我们还 ...
- layui 在页面弹出小窗口,并关闭
function showdialog() { layer.open({ type: 2, title: '发起调度', shadeClose: true, shade: 0.8, area: [ ...
- C# 构造基础返回值类型-BaseResponse
学无止境,精益求精 十年河东,十年河西,莫欺少年穷 用于基础返回值类型,如下: using System; using System.Collections.Generic; using System ...
- javascript实现blob加密视频源地址
一.HTML代码: <video id="my-video" class="video-js" playsinline controls preload= ...
- Java 之 Stack 集合
一.Stack:栈 概述 栈是一种先进后出(FILO)或后进先出(LIFO:Last in first out)的数据结构. Stack是Vector的子类,比Vector多了几个方法,它的后进先出的 ...
- Linux从入门到放弃、零基础入门Linux(第一篇):计算机操作系统简介、linux介绍
一.计算机操作系统简介 操作系统的定义: 操作系统是一个用来协调.管理和控制计算机硬件和软件资源的系统程序,它位于硬件和应用程序之间. 操作系统的内核的定义: 操作系统的内核是一个管理和控制程序,负责 ...
- CDH报错:PersistenceException: [PersistenceUnit: cmf.server] Unable to build EntityManagerFactory
1.在启动CDH中master的服务cloudera-scm-server start并立刻挂掉了,提示如下错误 org.springframework.beans.factory.BeanCreat ...
- 关于ORACLE图形化安装过程中出现的竖线的处理办法
这种情况上传个jre 并指定下就好了 ~/database/runInstaller -jreLoc /usr/local/jre1.8.0_191/
- eclipse设置序列化忽略生成serialVersionUID警告
java中的类想要序列化必须实现java.io.Serializable接口,一般实现接口都会用警告信息,提示生成serialVersionUID,虽然我觉得这个应该生成才合理.这里还是记录一下取消生 ...
- Java IO全面
转载请注明原文地址:https://www.cnblogs.com/ygj0930/p/10857412.html 一:IO流梳理——字符流.字节流.输入流.输出流 见另一篇博文:https://ww ...