当前位置 博文首页 > 不问前世:重新整理 .net core 实践篇—————配置系统之简单

    不问前世:重新整理 .net core 实践篇—————配置系统之简单

    作者:不问前世 时间:2021-06-05 18:24

    前言

    市面上已经有很多配置中心集成工具了,故此不会去实践某个框架。

    下面链接是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;
    

    直接返回本身即可。看到这里我们有时候也就不用太古板了,不是说非要分开两个类来实现。完全可以作为一个整体,也是极好的。

    上述只是个人整理,如有错误,望请指点。

    配置大概就整理到这里,后面写服务相关的,当然也会使用到前面这些微薄的原理(没有深入分析),就知道为什么服务配置要那么写了。

    下一节 服务与配置之间。

    bk
    下一篇:没有了