zoukankan      html  css  js  c++  java
  • .Net Core中的令牌ChangeToken、IChangeToken介绍

    ChangeToken是个静态类:

    public static class ChangeToken
    {
        public static IDisposable OnChange(Func<IChangeToken> changeTokenProducer, Action changeTokenConsumer);
    }

    该类仅仅提供了一个OnChange的静态方法,而该方法需要一个返回类型为IChangeToken的参数。而一看这个命名**Token,是不是很像CancellationToken,拥有了它,就会得到通知。 这种东西官方的名称其实叫做“令牌”。所以,您可能都会猜到,它可能会具有一个注册回调的方法:

    public interface IChangeToken
    {
        bool HasChanged { get; }
        bool ActiveChangeCallbacks { get; }
    
        IDisposable RegisterChangeCallback(Action<object> callback, object state);
    }

    那么,它存在的意义是什么呢? 高层的抽象! 

    比如下方的代码:

    Console.WriteLine("开始监测文件夹 c:\temp");
    
    var phyFileProvider = new PhysicalFileProvider("c:\temp");
    IChangeToken changeToken = phyFileProvider.Watch("*.*");
    changeToken.RegisterChangeCallback(_ =>
    {
        Console.WriteLine("检测到文件夹有变化!" + _);
    }, "xiaoming");

    像不像一个叫做PhysicalFileProvider的运营商,给我发了一个令牌。当我拥有这个令牌之后,运营商就可以联系到我了,当它联系我的时候,我就可以做出对应的反应。比如上面是打印一排字出来。

    而在“物理文件”这个圈子里面,IChangeToken的真身叫做PollingFileChangeToken;

    在“配置系统”这个圈子里面,IChangeToken的真身叫做ConfigurationReloadToken

    如果咱们想实现自己的IChangeToken怎么办呢?还记得最上面的CancellationTokenSource吗?既然.Net为咱们提供了一个线程安全而又直接可以拿来用的工具:

    public class MyOwnChangeToken : IChangeToken
    {
        public CancellationTokenSource _cts = new CancellationTokenSource();
    
        public bool ActiveChangeCallbacks => true;
    
        public bool HasChanged => _cts.IsCancellationRequested;
    
        public IDisposable RegisterChangeCallback(Action<object> callback, object state) => _cts.Token.Register(callback, state);
    
        public void MyOwnChange() => _cts.Cancel();
    }

    在“我自己的这个圈子”,就可以使用MyOwnChangeToken了,当外界获取到我的IChangeToken,我就可以触发MyOwnChange来通知他们了。

    其实.NET Core中大部分的IChangeToken内部都使用了CancellationTokenSource

    搞懂了IChangeToken我们就很轻松就能理解了ChangeToken,作为静态类的它,肯定是作为一个工具类的实现。

     ChangeToken.OnChange(
        () => physicalFileProvider.Watch("*.*"),
        () => Console.WriteLine("检测到文件夹有变化!")
    );

    那么您可能会说,我直接使用pysicalFileProvider.Watch()方法返回的IChangeToken的RegisterChangeCallback方法订阅不行吗?他们有什么区别吗? 答案是:“调用次数”。使用RegisterChangeCallback的方法,只会执行一次回调内容,因为当“令牌”用了一次之后,其实它就失效了。所以上面那个监控文件改动的代码,当第二次文件改动的时候,它其实是不会再执行回调的。

    而使用ChangeToken这个静态类,它就可以帮助您不断的去获取新“令牌”然后注册对应的回调,所以就能够保证咱们多次改变也能触发回调了。

    所以来看上面的这一段代码 ChangeToken.OnChange(() => physicalFileProvider.Watch("*.*"),...),“phyFileProvider”这个“供应商”可以为我们提供“令牌”,当该令牌发生改动的时候,我们就有机会去完成操作了。

    () => physicalFileProvider.Watch("*.*")这部分代码我们可以称它为“令牌生产过程”,而() => Console.WriteLine("检测到文件夹有变化!")叫做“令牌的消费过程”。

    ChangeToken 干的事情就是:当消费者消费之后,就又会去让“生产过程”再生成一个令牌出来,并且在该令牌上挂载“消费过程”,这样就能保证能够一直“观察”下去了。

    案例1:添加缓存时提供IChangeToken,当依赖文件修改时,删除缓存

    var fileProvider = new PhysicalFileProvider(Path.GetDirectoryName(dependencyFile));
    var changeToken = fileProvider.Watch(Path.GetFileName(dependencyFile));
    cache.Set(key, value, new MemoryCacheEntryOptions().AddExpirationToken(changeToken);

    案例2:配置文件统一读取类,当配置文件修改时,利用ChangeToken重新读取配置

        public class ConfigSetting
        {
            private IConfiguration _configuration = null;
            public ConfigSetting(IConfiguration configuration)
            {
                _configuration = configuration;
                ChangeToken.OnChange(()=>configuration.GetReloadToken(), () =>
                {
                    reloadConfiguration();
                });
                reloadConfiguration();
            }
            private void reloadConfiguration()
            {
                _siteName = _configuration["SiteName"];
                _siteID = _configuration.GetValue<int>("SiteID");
            }
    
            private string _siteName = null;
            private int _siteID = 0;
            public string SiteName
            {
                get{return _siteName;            }
            }
            public int SiteID
            {
                get{return _siteID;            }
            }
        }

     

    参考:https://www.cnblogs.com/uoyo/p/12509871.html

  • 相关阅读:
    没有内存,怎么还能跑程序呢
    风物长宜放眼量,人间正道是沧桑
    一篇文章带你「重新认识」线程上下文切换怎么玩儿
    一文带你怼明白进程和线程通信原理
    万字长文带你还原进程和线程
    这些操作系统的概念,保你没听过!
    什么叫操作系统啊 | 战术后仰
    你要问我应用层?我就和你扯扯扯
    面试官问你MyBatis SQL是如何执行的?把这篇文章甩给他
    从这道字符串处理的难题,寻找解决复杂问题的套路
  • 原文地址:https://www.cnblogs.com/fanfan-90/p/12772732.html
Copyright © 2011-2022 走看看