要清楚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 原理是什么?相关推荐

  1. Spring Cloud底层原理(转载 石杉的架构笔记)

    拜托!面试请不要再问我Spring Cloud底层原理 原创: 中华石杉 石杉的架构笔记 目录 一.业务场景介绍 二.Spring Cloud核心组件:Eureka 三.Spring Cloud核心组 ...

  2. Spring Cloud GateWay 原理

    Spring Cloud GateWay 原理 一.概述 在微服务架构中,每个服务都是一个可以独立开发和运行的组件,而一个完整的微服务架构由一系列独立运行的微服务组成.其中每个服务都只会完成特定领域的 ...

  3. Spring Cloud Feign原理

    Spring Cloud Feign原理 Feign运行过程 重试机制 服务降级 负载均衡 隔舱原理 Feign运行过程 通过主类上的EnableFeignClients 注解开启FeignClien ...

  4. Spring Cloud底层原理以及项目实战分析

    一.业务场景介绍 二.Spring Cloud核心组件------------------------------------------------------------------------- ...

  5. 面试官:说说Spring Cloud底层原理?

    点击上方"蓝字", 右上角选择"设为星标" 周一至周五上午11:45!精品文章准时送上! 本文转载自公众号:石杉的架构笔记 目录 一.业务场景介绍 二.Spri ...

  6. 面试请不要再问我Spring Cloud底层原理

    目录 一.业务场景介绍 二.Spring Cloud核心组件:Eureka 三.Spring Cloud核心组件:Feign 四.Spring Cloud核心组件:Ribbon 五.Spring Cl ...

  7. 第二十一期:拜托!面试不要再问我Spring Cloud底层原理

    毫无疑问,Spring Cloud 是目前微服务架构领域的翘楚,无数的书籍博客都在讲解这个技术. 不过大多数讲解还停留在对 Spring Cloud 功能使用的层面,其底层的很多原理,很多人可能并不知 ...

  8. 拜托!面试请不要再问我 Spring Cloud 底层原理 ...

    前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家.点击跳转到教程. >出处:  >https://www.fangzhipeng.com > 本文出自 ...

  9. spring cloud zuul 原理简介和使用

    一 spring cloud zuul 简介 Spring Cloud Zuul 是 Spring Cloud Netflix 子项目的核心组件之一,可以作为微服务架构中的 API 网关使用,支持动态 ...

最新文章

  1. 软件测试培训分享:如何划分bug的严重级别
  2. 半折预售:新书-R语言数据可视化之美|ggplot2作者推荐
  3. AS3与lua之间的交互
  4. 《算法设计编程实验:大学程序设计课程与竞赛训练教材》——2.3 构造法模拟的实验范例...
  5. 20165232 缓冲区溢出漏洞实验
  6. [你必须知道的.NET] 第一回:恩怨情仇:is和as
  7. Maven配置项目依赖使用本地仓库的方法汇总
  8. [Effective C++读书笔记]003_条款03_尽可能使用const
  9. Z-BlogPHP导航主题模版源码 绿色完美版
  10. Ibatis2.0使用说明(二)——配置篇
  11. 内置对象 API Math对象、Data对象、Array对象、String对象
  12. Android基础入门教程——4.3.2 BroadcastReceiver庖丁解牛
  13. seaweedfs java_seaweedfs-java-client
  14. JVM?干就完了!(一) - hello world
  15. 左神进阶班-KMP算法
  16. I'm coming now.
  17. 概率计算机在线,高斯正态分布(概率)计算公式与在线计算器_三贝计算网_23bei.com...
  18. 秋招总结帖,还愿牛客
  19. Debian 11 修改 DNS 服务器
  20. mathematica使用笔记

热门文章

  1. 《大话数据结构》第9章 排序 9.2 排序的基本概念与分类
  2. Netty系列(三):说说NioEventLoop
  3. @ConfigurationProperties 注解
  4. protobuf编码
  5. oracle如何清空一个用户下的所有表中的数据?
  6. Exchange 2007 迁移 2010
  7. 在本机上安装zabbix,来监控服务器 六
  8. 多重连弹の多层级联 下拉框/查找框级联操作
  9. 跨平台日志清理工具 Log-Cutter v1.0.3 正式发布
  10. 经典算法题每日演练——第二十一题 十字链表