前言
通常程式中配置少不了,配置的修改也避免不了,配置的熱更新為此給應用程式帶來很大的便捷,不用重啟,提高使用者體驗;但往往有時候需要對修改進行審計,也就是需要記錄,有時候也會針對配置修改的時候觸發相關操作,比如說發郵件通知,或是其他業務操作等,遇到這種情況,配置變更監聽的用處就體現出來了,接下來就嚐嚐鮮去;
正文
在看前兩篇文件的小夥伴可能會看到IConfiguration、IConfigurationProvider介面中有一個GetReloadToken()方法,之前只是註釋了一下,其實此方法返回的值就是變更通知的核心,如下圖的定義:
看看返回的IChangeToken裡定義了什麼
對於上面GetReloadToken其實最後返回的真正型別是ConfigurationReloadToken,繼承與IChangeToken,其作用就是為了通知程式:改變之後的配置源資料已經通過對應的IConfigurationProvider重新載入;看看其中是本質是啥?
通過以上程式碼顯示,其實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物件的方法來實現的,還是貼個圖吧,如下:
由ConfigurationRoot可見,觸發通知的方法RaiseChanged在ConfigurationRoot建構函式中(ConfigurationProvider對應的IChangeToken回撥中呼叫)及Reload的方法中進行呼叫,也就是說當IConfigurationProvider捕捉到配置源改變時會利用IChangeToken進行通知,或通過呼叫Reload方法載入時也會通知;
好了好了,理論就暫且說這麼多了,擼擼程式碼,看看是如何監聽的,話說在前頭,理論一大堆,使用很簡單,哈哈哈哈哈,控制檯程式走起來:
執行結果
經過上面案例演示,一個IChangeToken只能通知一次,需要多次建立,如果多次都是自己肯定很麻煩,所以微軟已經想到了,提供了一個靜態函式,如下程式碼優化即可:
執行結果:
靜態方法這種形式,就是ConfigurationRoot建構函式中IChangeToken監聽的方式,忘了的話往上再看看;
總結
有沒有被這節給忽悠了,一個這麼簡單的使用,還說那麼多"廢話",寫文字不累嗎? 我去,又過12點了,洗洗睡覺!!!!!;下次開始說說“Option”~~~
----------------------------------------------
一個被程式搞醜的帥小夥,關注"Code綜藝圈",跟我一起學~~~