• 跟我一起学.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

  • 相关阅读:
    根据svm将视频帧转换为img
    Mp4 to Img
    Python_02 基本数据类型、while循环
    Python_01 执行方式、解释器路径、编码、变量、条件语句
    数字货币,新时代货币革命的起点?
    企业区块链项目中需要避免的常见错误
    2021 年五大物联网 (IoT) 趋势
    揭开AI、机器学习和深度学习的神秘面纱
    物联网的安全性与法规的未来
    为什么分布式云是下一代云计算?Gartner分析师这样解释
  • 原文地址:https://www.cnblogs.com/zoe-zyq/p/13533131.html
Copyright © 2020-2023  润新知