跟我一起學.NetCore之配置變更監聽


前言

通常程序中配置少不了,配置的修改也避免不了,配置的熱更新為此給應用程序帶來很大的便捷,不用重啟,提高用戶體驗;但往往有時候需要對修改進行審計,也就是需要記錄,有時候也會針對配置修改的時候觸發相關操作,比如說發郵件通知,或是其他業務操作等,遇到這種情況,配置變更監聽的用處就體現出來了,接下來就嘗嘗鮮去;

正文

在看前兩篇文檔的小伙伴可能會看到IConfiguration、IConfigurationProvider接口中有一個GetReloadToken()方法,之前只是注釋了一下,其實此方法返回的值就是變更通知的核心,如下圖的定義:

img

看看返回的IChangeToken里定義了什么

img

對於上面GetReloadToken其實最后返回的真正類型是ConfigurationReloadToken,繼承與IChangeToken,其作用就是為了通知程序:改變之后的配置源數據已經通過對應的IConfigurationProvider重新加載;看看其中是本質是啥?

img

通過以上代碼顯示,其實ConfigurationReloadToken就是利用CancellationTokenSource在OnReload觸發的時候進行通知,這里暫且不深入再研究CancellationTokenSource了,不然感覺要跑題了(可以私下研究研究),停,趕緊回來;

大概了解到變更通知的原理,再來回顧一下配置IConfigurationRoot和IConfigurationSection,其實這兩個微軟其實已經實現了兩個類,ConfigurationRoot和ConfigurationSection,有默認的實現,簡單看看是如何實現的,稍微進行了重點注釋哦;

namespace Microsoft.Extensions.Configuration
{
    // 實現了IConfiguration 和ConfigurationRoot
    public class ConfigurationRoot : IConfigurationRoot, IConfiguration, IDisposable
    {
        // 用於存放注冊進來的IConfigurationProvider,Provider的作用還記得嗎?
        private readonly IList<IConfigurationProvider> _providers;
        // 默認創建一個ConfirationReloadToken,
        private ConfigurationReloadToken _changeToken = new ConfigurationReloadToken();
        // 提供一個_providers的訪問屬性
        public IEnumerable<IConfigurationProvider> Providers => _providers;
        // 實現中括號訪問,獲取配置值,看過前兩篇文章的應該知道都是用中括號的方式獲取值
        public string this[string key]
        {
            get
            {   // 注意,這里倒序遍歷,這樣就會導致相同Key,后注冊的配置源會覆蓋之前的
                for (int num = _providers.Count - 1; num >= 0; num--)
                {
                    if (_providers[num].TryGet(key, out string value))
                    {
                        return value;
                    }
                }
                return null;
            }
            set
            {
                if (!_providers.Any())
                {
                    throw new InvalidOperationException(Resources.Error_NoSources);
                }
                // 其實這里的設置值只是在內存里,沒有持久化
                foreach (IConfigurationProvider provider in _providers)
                {
                    provider.Set(key, value);
                }
            }
        }
        // 構造函數
        public ConfigurationRoot(IList<IConfigurationProvider> providers)
        {
            if (providers == null)
            {
                throw new ArgumentNullException("providers");
            }
            _providers = providers;
            _changeTokenRegistrations = new List<IDisposable>(providers.Count);
            // 遍歷所有有providers,加載數據
            foreach (IConfigurationProvider p in providers)
            {
                // 加載數據
                p.Load();
                // 注冊監聽及回調
                _changeTokenRegistrations.Add(ChangeToken.OnChange((Func<IChangeToken>)(() => p.GetReloadToken()), (Action)delegate
                {
                    // 通知
                    RaiseChanged();
                }));
            }
        }
        // 獲取通知Token
        public IChangeToken GetReloadToken()
        {
            return _changeToken;
        }
        // 重新加載數據 
        public void Reload()
        {
            // 遍歷所有provider進行重新加載數據
            foreach (IConfigurationProvider provider in _providers)
            {
                provider.Load();
            }
            // 發送通知
            RaiseChanged();
        }
        // 觸發通知
        private void RaiseChanged()
        {
            Interlocked.Exchange(ref _changeToken, new ConfigurationReloadToken()).OnReload();
        }
        ........省去一些方法......
    }
}

ConfigurationSection就不貼代碼,其實內部大多都是通過調用了IConfigrationRoot對象的方法來實現的,還是貼個圖吧,如下:

img

由ConfigurationRoot可見,觸發通知的方法RaiseChanged在ConfigurationRoot構造函數中(ConfigurationProvider對應的IChangeToken回調中調用)及Reload的方法中進行調用,也就是說當IConfigurationProvider捕捉到配置源改變時會利用IChangeToken進行通知,或通過調用Reload方法加載時也會通知;

好了好了,理論就暫且說這么多了,擼擼代碼,看看是如何監聽的,話說在前頭,理論一大堆,使用很簡單,哈哈哈哈哈,控制台程序走起來:

img

運行結果

img

經過上面案例演示,一個IChangeToken只能通知一次,需要多次創建,如果多次都是自己肯定很麻煩,所以微軟已經想到了,提供了一個靜態函數,如下代碼優化即可:

img

運行結果:

img

靜態方法這種形式,就是ConfigurationRoot構造函數中IChangeToken監聽的方式,忘了的話往上再看看;

總結

有沒有被這節給忽悠了,一個這么簡單的使用,還說那么多"廢話",寫文字不累嗎? 我去,又過12點了,洗洗睡覺!!!!!;下次開始說說“Option”~~~

----------------------------------------------

一個被程序搞丑的帥小伙,關注"Code綜藝圈",跟我一起學~~~

img


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM