十二、Nacos源码系列:Nacos配置中心原理(四)- RefreshEvent 事件处理

前面文章,我们说到回调监听器的方法中,主要就是发布了一个RefreshEvent事件,这个事件主要由 SpringCloud 相关类来处理。今天我们继续分析后续的流程。

RefreshEvent 事件会由 RefreshEventListener 来处理,该 listener 含有一个 ContextRefresher 的对象。

public void onApplicationEvent(ApplicationEvent event) {if (event instanceof ApplicationReadyEvent) {handle((ApplicationReadyEvent) event);}else if (event instanceof RefreshEvent) {handle((RefreshEvent) event);}
}public void handle(RefreshEvent event) {if (this.ready.get()) { // don't handle events before app is readylog.debug("Event received " + event.getEventDesc());// private ContextRefresher refreshSet<String> keys = this.refresh.refresh();log.info("Refresh keys changed: " + keys);}
}// org.springframework.cloud.context.refresh.ContextRefresher#refresh
public synchronized Set<String> refresh() {// 刷新Environment环境信息Set<String> keys = refreshEnvironment();this.scope.refreshAll();return keys;
}public synchronized Set<String> refreshEnvironment() {Map<String, Object> before = extract(this.context.getEnvironment().getPropertySources());// 添加配置内容到环境对象中addConfigFilesToEnvironment();Set<String> keys = changes(before,extract(this.context.getEnvironment().getPropertySources())).keySet();// 发布EnvironmentChangeEvent事件(环境变更事件)this.context.publishEvent(new EnvironmentChangeEvent事件(this.context, keys));return keys;
}

从源码可以看到,refreshEnvironment 会去刷新 Spring 环境变量,具体刷新思想就是重新创建一个Environment,然后将这个新的环境信息设置到原有的 Spring 环境中。拿到所有变化的配置项后,发布一个环境变化的 EnvironmentChangeEvent(环境变更事件)事件。

ConfigurationPropertiesRebinder 会监听 EnvironmentChangeEvent 事件,监听到事件后会对所有的标注有 ConfigurationProperties 注解的配置类进行销毁后重新初始化的操作,完成后我们的配置类中的属性就是最新的了。

// org.springframework.cloud.context.properties.ConfigurationPropertiesRebinder#onApplicationEvent
public void onApplicationEvent(EnvironmentChangeEvent event) {if (this.applicationContext.equals(event.getSource())// Backwards compatible|| event.getKeys().equals(event.getSource())) {rebind();}
}

 

// 所有的标注有 ConfigurationProperties 注解的配置类
private ConfigurationPropertiesBeans beans;
public ConfigurationPropertiesRebinder(ConfigurationPropertiesBeans beans) {this.beans = beans;
}public void rebind() {this.errors.clear();for (String name : this.beans.getBeanNames()) {rebind(name);}
}public boolean rebind(String name) {if (!this.beans.getBeanNames().contains(name)) {return false;}if (this.applicationContext != null) {try {Object bean = this.applicationContext.getBean(name);if (AopUtils.isAopProxy(bean)) {bean = ProxyUtils.getTargetObject(bean);}if (bean != null) {// TODO: determine a more general approach to fix this.// see https://github.com/spring-cloud/spring-cloud-commons/issues/571if (getNeverRefreshable().contains(bean.getClass().getName())) {return false; // ignore}// 销毁beanthis.applicationContext.getAutowireCapableBeanFactory().destroyBean(bean);// 重新初始化beanthis.applicationContext.getAutowireCapableBeanFactory().initializeBean(bean, name);return true;}}catch (RuntimeException e) {this.errors.put(name, e);throw e;}catch (Exception e) {this.errors.put(name, e);throw new IllegalStateException("Cannot rebind to " + name, e);}}return false;
}

上述代码只会对标有 ConfigurationProperties 注解的配置类进行rebind,那对于普通组件类里标有 @Value 注解的属性要怎么生效呢?这个其实需要配合 @RefreshScope 注解来生效的。

我们继续回到前面处理RefreshEvent事件的ContextRefresher#refresh()方法,接着会有一步 refreshAll 的操作,会调用父类的destroy()方法。

public synchronized Set<String> refresh() {Set<String> keys = refreshEnvironment();// private RefreshScope scope;this.scope.refreshAll();return keys;
}// org.springframework.cloud.context.scope.refresh.RefreshScope#refreshAll
public void refreshAll() {// 调用父类的销毁方法:org.springframework.cloud.context.scope.GenericScope#destroy()super.destroy();this.context.publishEvent(new RefreshScopeRefreshedEvent());
}

父类就是 GenericScope,我们知道 Spring 中的 Bean 是有Scope 的概念的,Spring 默认 Scope 有单例和原型两种,同时提供了 Scope 扩展接口,通过实现该接口我们可以定义自己的 Scope。

在Spring IOC容器初始化的时候,doGetBean()方法中,这些自定义 Scope 类型对象的管理会交给相应的 Scope 实现去管理。

SpringCloud 实现的 RefreshScope 就是用来在运行时动态刷新 Bean 用的,RefreshScope 继承 GenericScope,提供 get()和 destroy()方法。

回到refreshAll()方法,在 refreshAll()中调用 super.destroy()方法时会将该 scope 的这些 Bean 都销毁掉,在下次 get()的时候会重新新触发spring的createBean,创建出一个新的bean对象,新创建的 Bean 就有了我们最新的配置。

// org.springframework.cloud.context.scope.GenericScope#get
public Object get(String name, ObjectFactory<?> objectFactory) {BeanLifecycleWrapper value = this.cache.put(name,new BeanLifecycleWrapper(name, objectFactory));this.locks.putIfAbsent(name, new ReentrantReadWriteLock());try {// 会重新触发spring的createBean,创建出一个新的bean对象,填充进去的属性就是最新配置的内容return value.getBean();}catch (RuntimeException e) {this.errors.put(name, e);throw e;}
}

至此,我们就实现了配置的热更新。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/716937.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Object类方法

toString(): 返回对象的字符串表示形式。默认情况下&#xff0c;返回对象的类名和哈希码的十六进制表示。 equals(Object obj): 比较两个对象是否相等。默认情况下&#xff0c;这个方法比较的是两个对象的引用是否相同&#xff0c;但是通常会在子类中重写这个方法以实现自定义…

武器大师——操作符详解(下)

目录 六、单目操作符 七、逗号表达式 八、下标引用以及函数调用 8.1.下标引用 8.2.函数调用 九、结构体 9.1.结构体 9.1.1结构的声明 9.1.2结构体的定义和初始化 9.2.结构成员访问操作符 9.2.1直接访问 9.2.2间接访问 十、操作符的属性 10.1.优先性 10.2.结合性 …

sql基本语法+实验实践

sql语法 注释&#xff1a; 单行 --注释内容# 注释内容多行 /* 注释内容 */数据定义语言DDL 查询所有数据库 show databases;注意是databases而不是database。 查询当前数据库 select database();创建数据库 create database [if not exists] 数据库名 [default charset 字符…

备战蓝桥杯Day22 - 计数排序

计数排序问题描述 对列表进行排序&#xff0c;已知列表中的数范围都在0-100之间。设计时间复杂度为O(n)的算法。 比如列表中有一串数字&#xff0c;2 5 3 1 6 3 2 1 &#xff0c;需要将他们按照从小到大的次序排列&#xff0c;得到1 1 2 2 3 3 5 6 的结果。那么此时计数排序是…

一:面试流程

面试 项目介绍功能测试接口测试性能测试测试用例 项目介绍 南网智搜是南方电网公司研发的搜索引擎&#xff0c;主要场景Web 端场景有搜索频道、个人中心、和一些积分活动等&#xff0c;我在里面主要负责功能测试&#xff0c;接口测试&#xff0c;性能测试&#xff0c;压力测试…

Jetson Xavier NX 开发板Ubuntu18.04 安装arduino IDE详细步骤

Jetson 平台是arch架构&#xff0c;官网上面几乎都是x86或者arm64的这两种错误版本都存在匹配问题无法使用&#xff0c;不要下载不要下载&#xff01; uname -a #版本查询1.正确下载打开方式 https://downloads.arduino.cc/arduino-1.8.19-linuxaarch64.tar.xz选择自己想要下…

LeetCode #104 二叉树的最大深度

104. 二叉树的最大深度 题目 二叉树的 最大深度 是指从根节点到最远叶子节点的最长路径上的节点数。 示例 1&#xff1a; 输入&#xff1a;root [3,9,20,null,null,15,7] 输出&#xff1a;3 示例 2&#xff1a; 输入&#xff1a;root [1,null,2] 输出&#xff1a;2 分析 …

【Godot4自学手册】第十九节敌人的血量显示及掉血特效

这一节&#xff0c;我主要学习敌人的血量显示、掉血显示和死亡效果。敌人的血量显示和主人公的血量显示有所不同&#xff0c;主要是在敌人头顶有个红色的血条&#xff0c;受到攻击敌人的血条会减少&#xff0c;并且有掉血数量的文字显示&#xff0c;效果如下&#xff1a; 一、…

《中华人民共和国消防法》(2021年修订版)解读

单选题&#xff08;共7题&#xff0c;每题5分&#xff09; 1、举办大型群众性活动&#xff0c;承办人应当依法向&#xff08;&#xff09;申请安全许可。 正确答案&#xff1a;B、公安机关 2、违反消防安全规定进入生产、储存易燃易爆危险品场所的&#xff0c;情节严重的要处…

基于springboot+vue的医院后台管理系统

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、阿里云专家博主、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战&#xff0c;欢迎高校老师\讲师\同行交流合作 ​主要内容&#xff1a;毕业设计(Javaweb项目|小程序|Pyt…

胎神游戏集第一期

目录 一、变色小跳龙 二、超级按钮 三、超级迷宫 四 、城市守卫战 五、 愤怒的小胎 既然是胎神游戏集&#xff0c;那当然要先感谢我们的胎神大大了 胎神洛谷名&#xff1a;TSzza 好了&#xff0c;言归正传&#xff0c;知道你们不喜欢啰嗦&#xff0c;直接上代码 一、…

SMBGhost漏洞技术分析与防御方案

事件分析 最近国内外各安全厂商都发布了SMBGhost(CVE-2020-0796)漏洞的预警报告和分析报告&#xff0c;笔者利用周末休息时间也研究了一下&#xff0c;就算是做一个笔记了&#xff0c;分享给大家一起学习下&#xff0c;目前外面研究的POC大部分是通过SMB压缩数据包长度整数溢出…

【openGL4.x手册04】基元

一、说明 OpenGL 中的术语“基元”用于指代两个相似但独立的概念。 “原语”的第一个含义是指 OpenGL 使用的解释方案来确定渲染时顶点流所代表的内容&#xff0c;例如“GL_POINTS”。这样的顶点序列可以是任意长的。 “原语”的另一个含义&#xff0c;也称为“基本原语”&…

如何根据玩家数量和游戏需求选择最合适的服务器配置?

根据玩家数量和游戏需求选择最合适的服务器配置&#xff0c;首先需要考虑游戏的类型、玩家数量、预计的在线时间以及对内存和CPU性能的需求综合考虑。对于大型多人在线游戏&#xff0c;如MMORPG或MOBA等&#xff0c;由于需要更多的CPU核心数来支持更复杂的游戏逻辑和处理大量数…

操作系统|概述|系统分类——笔记

1.1_1操作系统的概念和功能 操作系统的概念 操作系统&#xff08;Operating System&#xff0c; OS&#xff09; 是指控制和管理整个计算机系统的 硬件和软件 资源&#xff0c;并合理地组织调度计算机和工作和资源的分配&#xff1b; 1操作系统是系统资源的管理者 以提供给用…

springboot拦截器和过滤器

过滤器 Filter依赖于servlet容器&#xff0c;属于servlet规范的一部分 Filter的生命周期由servlet容器管理 Filter可拦截所有web资源(包括jsp&#xff0c;Servlet&#xff0c;静态资源&#xff0c;Controller) 自定义Filter import javax.servlet.*; WebFilter(urlPatterns …

文件的顺序读写函数举例介绍

目录 例1&#xff1a;&#xff08;使用字符输出函数fputc&#xff09;例2&#xff1a;&#xff08;使用字符输入函数fgetc&#xff09;例3&#xff1a;&#xff08;使用文本行输出函数fputs &#xff09;例4&#xff1a;&#xff08;使用文本行输入函数fgets &#xff09;例5&a…

Docker基础教程 - 2 Docker安装

更好的阅读体验&#xff1a;点这里 &#xff08; www.doubibiji.com &#xff09; 2 Docker安装 Docker 的官网地址&#xff1a;https://www.docker.com/&#xff0c;在官网可以找到 Docker Engine 的安装步骤。 下面进行 Docker 环境的安装&#xff0c;正常情况下 Docker …

服务发现:CP or AP?

1 服务发现的意义 为高可用&#xff0c;生产环境中服务提供方都以集群对外提供服务&#xff0c;集群里这些IP随时可能变化&#xff0c;也需要用一本“通信录”及时获取对应服务节点&#xff0c;这获取过程即“服务发现”。 对服务调用方和服务提供方&#xff0c;其契约就是接…

(3)(3.1) FlightDeck FrSky发射器应用程序

文章目录 前言 1 概述 2 Turnkey Packages 3 参数说明 前言 ​Craft and Theory 的 FlightDeck 可让你轻松查看飞行模式、高度、速度、姿态和关键系统警报&#xff0c;包括故障保护和电池错误&#xff0c;如电池不平衡警告和发射机低电量警报。 1 概述 Craft and Theory 的…