前言
市面上已經有很多配置中心整合工具了,故此不會去實踐某個框架。
下面連結是apollo 官網的教程,實在太詳細了,本文介紹一下擴充套件資料來源,和簡單翻翻閱一下apollo 關鍵部分。
apollo 服務配置:
https://github.com/ctripcorp/apollo/wiki/.Net客戶端使用指南
apollo .net 客戶端配置:
https://github.com/ctripcorp/apollo.net/tree/dotnet-core/Apollo.Configuration
正文
擴充套件資料來源
經過前面的系列的原始碼解讀,我們知道我們需要去實現IConfigurationSource,IConfigurationProvider。
他們的關係是IConfigurationSource build 方法會構建出IConfigurationProvider,IConfigurationProvider 會為 IConfigurationRoot 提供資料來源。
好的,那麼開始吧。
RemoteConfigurationSource 實現 IConfigurationSource:
public class RemoteConfigurationSource : IConfigurationSource
{
public RemoteConfigurationProvider _provider;
public RemoteConfigurationProvider Provider
{
get
{
if (_provider == null)
{
_provider = new RemoteConfigurationProvider();
}
return _provider;
}
}
public IConfigurationProvider Build(IConfigurationBuilder builder)
{
return this.Provider;
}
}
IConfigurationProvider 繼承ConfigurationProvider:
public class RemoteConfigurationProvider : ConfigurationProvider
{
public RemoteConfigurationProvider():base()
{
}
public override void Load()
{
this.Data["name"] = "zhangshan";
Load(false);
}
public void Load(bool reload)
{
if (reload)
{
this.OnReload();
}
}
}
這裡沒有繼承IConfigurationProvider而是繼承ConfigurationProvider的原因,是因為ConfigurationProvider實現基於字典的資料來源實現,這裡演示比較方便。
static void Main(string[] args)
{
IConfigurationBuilder builder = new ConfigurationBuilder();
var selfSource = new RemoteConfigurationSource();
builder.Add(selfSource);
var root = builder.Build();
Console.WriteLine($"name: {root["name"]}");
ChangeToken.OnChange(() => root.GetReloadToken(), () =>
{
Console.WriteLine($"reload name: {root["name"]}");
});
selfSource.Provider.Set("name","lisi");
selfSource.Provider.Load(true);
Console.ReadKey();
}
這裡只是作為演示,實際上我們可以通過在RemoteConfigurationProvider 做監聽,然後收到通知後,進行reload 呼叫即可,在configurationProvider中的reload如下:
private ConfigurationReloadToken _reloadToken = new ConfigurationReloadToken();
protected void OnReload()
{
ConfigurationReloadToken previousToken = Interlocked.Exchange(ref _reloadToken, new ConfigurationReloadToken());
previousToken.OnReload();
}
觸發令牌更新,然後令牌會觸發回撥。
那麼來看下apollo 第三方元件怎麼寫的吧。
引入這個包: Com.Ctrip.Framework.apollo.Configuration
public class ApolloConfigurationProvider : ConfigurationProvider, IRepositoryChangeListener, IConfigurationSource
{
internal string? SectionKey { get; }
internal IConfigRepository ConfigRepository { get; }
private Task? _initializeTask;
public ApolloConfigurationProvider(string? sectionKey, IConfigRepository configRepository)
{
SectionKey = sectionKey;
ConfigRepository = configRepository;
ConfigRepository.AddChangeListener(this);
_initializeTask = ConfigRepository.Initialize();
}
public override void Load()
{
Interlocked.Exchange(ref _initializeTask, null)?.ConfigureAwait(false).GetAwaiter().GetResult();
SetData(ConfigRepository.GetConfig());
}
protected virtual void SetData(Properties properties)
{
var data = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
foreach (var key in properties.GetPropertyNames())
{
if (string.IsNullOrEmpty(SectionKey))
data[key] = properties.GetProperty(key) ?? string.Empty;
else
data[$"{SectionKey}{ConfigurationPath.KeyDelimiter}{key}"] = properties.GetProperty(key) ?? string.Empty;
}
Data = data;
}
void IRepositoryChangeListener.OnRepositoryChange(string namespaceName, Properties newProperties)
{
SetData(newProperties);
OnReload();
}
IConfigurationProvider IConfigurationSource.Build(IConfigurationBuilder builder) => this;
}
裡面有這個OnRepositoryChange 監聽,如果收到監聽資訊然後就觸發設定資料,然後呼叫OnReload 觸發令牌過期,也就是觸發通知。
有些人肯定問啊,肯定要有IconfigurationSource啊,在哪呢? 看這個設計ApolloConfigurationProvider 繼承了IConfigurationSource介面。
ApolloConfigurationProvider實現的build(上面貼了)如下:
IConfigurationProvider IConfigurationSource.Build(IConfigurationBuilder builder) => this;
直接返回本身即可。看到這裡我們有時候也就不用太古板了,不是說非要分開兩個類來實現。完全可以作為一個整體,也是極好的。
結
上述只是個人整理,如有錯誤,望請指點。
配置大概就整理到這裡,後面寫服務相關的,當然也會使用到前面這些微薄的原理(沒有深入分析),就知道為什麼服務配置要那麼寫了。
下一節 服務與配置之間。