十二、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.pswp.cn/news/716937.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/716937.shtml
英文地址,請注明出處:http://en.pswp.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 的…