.NET Core採用的全新配置系統[10]: 配置的同步機制是如何實現的?

来源:http://www.cnblogs.com/artech/archive/2016/08/18/new-config-system-10.html
-Advertisement-
Play Games

配置的同步涉及到兩個方面:第一,對原始的配置文件實施監控併在其發生變化之後從新載入配置;第二,配置重新載入之後及時通知應用程式進而使後者能夠使用最新的配置。要瞭解配置同步機制的實現原理,先得從認識一個名為ConfigurationReloadToken的類型開始。 ...


配置的同步涉及到兩個方面:第一,對原始的配置文件實施監控併在其發生變化之後從新載入配置;第二,配置重新載入之後及時通知應用程式進而使後者能夠使用最新的配置。要瞭解配置同步機制的實現原理,先得從認識一個名為ConfigurationReloadToken的類型開始。 [ 本文已經同步到《ASP.NET Core框架揭秘》之中]

目錄
一、從ConfigurationReloadToken說起
二、Configuration對象與配置文件的同步
三、應用重新載入的配置
四、同步流程總結

一、從ConfigurationReloadToken說起

.NET Core絕大部分的數據同步場景下都使用到一個名為ChangeToken的對象,該對象綁定到某個需要被監控的對象,並該對象發生改變是對外發送通知,我們可以註冊在被監控數據發生改變時可以自動執行的回調。在配置同步場景中,ConfigurationProvider會利用FileProvider監控配置文件的變化,併在變化時從新載入配置。ConfigurationReloadToken就是一個通知配置已經被重新載入的ChangeToken。

ConfigurationReloadToken本質上是對一個CancellationTokenSource對象的封裝。如果我們對.NET基於Task對象的並行/非同步編程有所瞭解的話,相信對CancellationTokenSource應該不會感到模式。總的來說,我們可以利用CancellationTokenSource創建的CancellationToken向某個非同步執行的Task發送“取消任務”的信號。如下麵的代碼片段所示,ConfigurationReloadToken的HasChanged屬性對應的是這個CancellationTokenSource對象的IsCancellationRequested。通過調用RegisterChangeCallback方法註冊的回調實際上是註冊到 CancellationTokenSource創建的CancellationToken對象上。

   1: public class ConfigurationReloadToken : IChangeToken
   2: {
   3:     private CancellationTokenSource _cts = new CancellationTokenSource();
   4:  
   5:     public void OnReload()
   6:     {
   7:         _cts.Cancel();
   8:     }
   9:  
  10:     public IDisposable RegisterChangeCallback(Action<object> callback, object state)
  11:     {
  12:         return _cts.Token.Register(callback, state);
  13:     }
  14:     
  15:     public bool ActiveChangeCallbacks
  16:     {
  17:         get { return true; }
  18:     }
  19:  
  20:     public bool HasChanged
  21:     {
  22:         get { return _cts.IsCancellationRequested; }
  23:     }
  24: }

當ConfigurationReloadToken的OnReload方法被執行的時候,這被封裝的CancellationTokenSource對象的Cancel方法隨之被調用。我們知道一旦這個Cancel方法被調用之後,CancellationTokenSource的IsCancellationRequested會馬上變成True,意味著ConfigurationReloadToken的HasChanged屬性也立即變成True。由於調用RegisterChangeCallback方法註冊的回調最是註冊到CancellationTokenSource創建的CancellationToken上的,所以該回調會在OnLoad方法被調用之後自動執行。

二、Configuration對象與配置文件的同步

在《聊聊預設支持的各種配置源》和《深入瞭解三種針對文件(JSON、XML與INI)的配置源》中,我們介紹了系統預定義的若幹配置源,它們都通過相應的ConfigurationSource類型來表示,對於這些ConfigurationSource來說,只有針對配置文件的FileConfigurationSource才會涉及到配置同步的問題。其實這一點也可以由它們的定義看出來,因為只有FileConfigurationSource這個抽象類才定義瞭如下這個ReloadOnChange屬性來控制當配置文件改變之後是否需要重新載入配置。換句話說,配置的同步首先需要解決的是由ConfigurationBuilder創建的Configuration對象與原始配置文件的內容同步的問題,而解決這個問題的途徑就是對配置實施監控,併在文件發生改變之後自動重新載入配置。

   1: public abstract class FileConfigurationSource : IConfigurationSource
   2: {
   3:     ...
   4:     public bool ReloadOnChange { get; set; }
   5: }

我們知道 FileConfigurationProvdier總是利用一個FileProvider對象來讀取對應的配置文件,除了讀取文件內容之外,FileProvider的Watch方法自身就提供了文件監控的能力。FileConfigurationProvdier利用FileProvider監控配置文件,併在配置文件發生改變時自動載入配置的操作實現在如下所示的代碼片段中。

   1: public abstract class FileConfigurationProvider : ConfigurationProvider
   2: {
   3:     ...
   4:     public FileConfigurationProvider(FileConfigurationSource source)
   5:     {
   6:         this.Source = source;
   7:         if (source.ReloadOnChange && (this.Source.FileProvider != null))
   8:         {
   9:             ChangeToken.OnChange(() => source.FileProvider.Watch(source.Path), this.Load);
  10:         }
  11:     }
  12: }


三、應用重新載入的配置

Configuration對象與配置文件的同步問題解決之後,還需要讓應用程式感知到使用的Configuration對象已經發生改變,並且使之能夠將新的配置應用到程式之中。從編程的角度來講,這個問題很容易解決,我們只需要調用Configuration對象的GetReloadToeken方法得到一個ChangeToken對象,並將重新應用配置的操作註冊作為回調註冊到這個ChangeToken上面就可以了。

   1: public interface IConfiguration
   2: {
   3:     ...
   4:     IChangeToken GetReloadToken();
   5: }

程式應用重新配置的回調是註冊到Configuration對象的GetReloadToken方法返回的ChangeToken對象上,而Configuration對象的重新載入最終是通過調用所有ConfigurationProvider的Load方法來實現的,所以兩者之間必然存在著某種聯繫。說的具體一點,應用程式可以通過這個ChangeToken感知到配置系統針對ConfigurationProvider的Load方法的調用。要瞭解兩者之間的聯繫,我們必須先弄清楚Configuration的 GetReloadToken方法返回的是怎樣一個ChangeToken對象。

一個Configuration對象代表配置樹的某個節點,對於組成同一棵配置樹的所有Configuration對象來說,它們的GetReloadToken方法返回的ChangeToken都來源於代表根節點的ConfigurationRoot對象。說的更加具體一點,當我們調用它們的GetReloadToken的時候,返回的其實是調用ConfigurationRoot的同名方法的返回值,那麼我們有必要瞭解一下ConfigurationRoot的GetReloadToken方法的邏輯。

   1: public class ConfigurationRoot : IConfigurationRoot
   2: {
   3:     private ConfigurationReloadToken _changeToken = new ConfigurationReloadToken();
   4:     private IList<IConfigurationProvider> _providers;
   5:  
   6:     public ConfigurationRoot(IList<IConfigurationProvider> providers)
   7:     {
   8:         _providers = providers;
   9:  
  10:         foreach (var provider in providers)
  11:         {
  12:             provider.Load();
  13:             ChangeToken.OnChange(() => provider.GetReloadToken(), this.RaiseChanged);
  14:         }        
  15:     }    
  16:  
  17:     public IChangeToken GetReloadToken()
  18:     {
  19:         return _changeToken;
  20:     }
  21:  
  22:     private void RaiseChanged()
  23:     {
  24:         Interlocked.Exchange<ConfigurationReloadToken>(ref _changeToken, new ConfigurationReloadToken()).OnReload();
  25:     }
  26:  
  27:     public void Reload()
  28:     {
  29:         foreach (var provider in _providers)
  30:         {
  31:             provider.Load();
  32:         }
  33:         this.RaiseChanged();
  34:     }    
  35: }

如上面的代碼片段所示,ConfigurationRoot的GetReloadToken方法返回的是通過欄位_changeToken表示的一個ConfigurationReloadToken對象。私有方法RaiseChanged通過調用ConfigurationReloadToken對象的OnReload向訂閱者發送配置重新被載入的通知,由於ChangeToken只能使用一次,所以該方法總是為_changeToken欄位附上一個新的ConfigurationReloadToken對象。

針對這個RaiseChanged方法的調用發生在兩個地方,第一個地方發生在ConfigurationRoot的Reload方法上,也就是說當我們調用該方法以手工的方式重新載入配置的時候,註冊到Configuration對象提供的ChangeToken上的回調也會自動執行。

針對RaiseChanged方法的調用還出現在ConfigurationRoot構造函數中。如上面的代碼片段所示,ConfigurationRoot會調用每個ConfigurationProvdier的GetReloadToken方法,並將針對RaiseChanged方法的調用作為回調註冊到返回的ChangeToken上,也就是說註冊到Configuration對象提供的ChangeToken上的回調實際上註冊到ConfigurationProvider提供的ChangeToken上。既然如此,如果 ConfigurationProvider提供的這個ChangeToken能夠反映針對Load方法的調用,那麼上面提到的關於Configuration提供的ChangeToken與ConfigurationProvider的Load方法之間的聯繫就建立起來了。那麼ConfigurationProvider的Load方法與ChangeToken方法返回的ChangeToken究竟有沒有關係呢?

   1: public abstract class ConfigurationProvider : IConfigurationProvider
   2: {
   3:     private ConfigurationReloadToken _reloadToken = new ConfigurationReloadToken();
   4:  
   5:     public IChangeToken GetReloadToken()
   6:     {
   7:         return_reloadToken;
   8:     }
   9:  
  10:     protected void OnReload()
  11:     {
  12:         Interlocked.Exchange<ConfigurationReloadToken>(ref_reloadToken, new ConfigurationReloadToken()).OnReload();
  13:     }
  14: }

如上面的代碼片段所示,抽象類ConfigurationProvider的GetRealoadToken方法返回的是一個通過欄位_reloadToken表示的ConfigurationReloadToken對象。該類型還定義了一個受保護的OnReload方法,該方法具有與上面介紹的RaiseChanged方法一樣的邏輯,意味著ConfigurationProvider實際上是調用這個方法對外發送配置被重新載入的通知。針對這個OnLoad方法的調用發生在FileConfigurationProvider的Load方法中。所以上面提到的讓ConfigurationProvider提供的ChangeToken能夠反映針對Load方法的調用最終實現在FileConfigurationProvider中。

   1: public abstract class FileConfigurationProvider : ConfigurationProvider
   2: {
   3:     ...
   4:     public override void Load()
   5:     {
   6:         ...
   7:         base.OnReload();
   8:     }
   9: }


四、同步流程總結

上面我們通過代碼分析的方式捋清了配置文件在發生改變的時候為什麼會導致配置的重新載入,註冊到Configuration通過GetRealoadToken方法提供的ChangeToken上的回調為什麼會自動執行。可能都有讀者的腦子裡面還是比較暈,所以我們利用如下所示的序列圖繼續對這個過程進行講解。用於讀取配置文件內容的FileConfigurationProvder會調用FileProvder的Watch方法來監控文件的變化(實際上真正用於文件監控的實PhysicalFileProvider所示用的FileSystemWatcher),並且通過向返回的ChangeToken註冊回調的方式來調用自身的Load方法來實現配置配置的重新載入。

  14

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 很多kali愛好者想把kali linux作為系統使用,但是有些win下的程式有時候也需要用到,此時需要虛擬機。 kali系統在安裝虛擬機的時候也會遇到一大堆坑,接下來是我的爬坑過程。 一波三折。 環境 :kali linux 2.0 32位 軟體 :virtualbox 虛擬機 0x01 bash ...
  • typedef struct _IMAGE_EXPORT_DIRECTORY { DWORD Characteristics; // 未使用,總為0 DWORD TimeDateStamp; // 文件創建時間戳 WORD MajorVersion; // 未使用,總為0 WORD MinorVer... ...
  • Touch ID是iPhone5S後加入的一項新的功能,也就是大家熟知的指紋識別技術。大家用得最多的可能是手機的解屏操作,不用在和以前一樣輸入手機的四位數密碼進行驗證。一方面不用擔心密碼被別人看到,另一方面也方便了自己的操作。iOS8後蘋果開放了Touch ID的API給開發者,這也給我們的app帶 ...
  • 如果你對iOS逆向工程有所瞭解,那麼你對Tweak並不陌生。那麼由Tweak我們又會引出Theos, 那麼什麼是Theos呢,簡單一句話,Theos是一個越獄開發工具包,Theos是越獄開發工具的首先,因為其最大的特點就是簡單。大道至簡,Theos的下載安裝、編譯發佈都比較簡單,越獄開發中另一個常用 ...
  • 一,效果圖。 二,工程圖。 三,代碼。 AppDelegate.m ...
  • 調用相機拍照獲取圖片: 跳轉到到拍照界面: Intent takeIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); //下麵這句指定調用相機拍照後的照片存儲的路徑 mSzImageFileName = Long.toString(System ...
  • 高效計算——RenderScript RenderScript是安卓平臺上很受谷歌推薦的一個高效計算平臺,它能夠自動把計算任務分配到各個可用的計算核心上,包括CPU,GPU以及DSP等,提供十分高效的並行計算能力。可能是由於應用開發時的需求不夠,關於RenderScript的相關文章很少,剛好我在工 ...
  • 框架簡介 這幾年一直在做ASP.NET開發,幾年前做項目都是老老實實一行行的寫代碼,後來發現那些高手基本都會有自己積累起來的代碼庫,現在稱之為開發框架,基礎代碼不用再去堆,主要精力可以集中在業務邏輯實現上。這樣開發效率高了,他們的待遇也會比我高出很多。我也想有自己的房子、車子、妹子,我也想成為開發高 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...