• [Asp.net 5] Options-配置文件(2)


    很久之前写过一篇介绍Options的文章,2016年再打开发现很多变化。增加了新类,增加OptionMonitor相关的类。今天就对于这个现在所谓的新版本进行介绍。

    老版本的传送门([Asp.net 5] Options-配置文件之后昂的配置)。

    首先上一个图:

    *绿线是继承关系,蓝线是关联关系。

    我们把上面切成2大部分。

    Option部分

    这部分分为俩部分,第一部分直接创建Options,该部分通过Options静态类创建一个OptionsWrapper类,之后将(IOptions,OptionsWrapper)进行注入。这部分是DI的实体注入,很简单,没有什么可说的,此处应用非常常见的“工厂模式”。

    第二部分是将(IOptions,OptionsManager)进行注入。我们OptionsManager会使用IEnumerable<IConfigureOptions<TOptions>>作为参数,而内部返回的是OptionsCache类型的对象,此处应用非常常见的“代理模式

        internal class OptionsCache<TOptions> where TOptions : class, new()
        {
            private readonly Func<TOptions> _createCache;
            private object _cacheLock = new object();
            private bool _cacheInitialized;
            private TOptions _options;
            private IEnumerable<IConfigureOptions<TOptions>> _setups;
    
            public OptionsCache(IEnumerable<IConfigureOptions<TOptions>> setups)
            {
                _setups = setups;
                _createCache = CreateOptions;
            }
    
            private TOptions CreateOptions()
            {
                var result = new TOptions();
                if (_setups != null)
                {
                    foreach (var setup in _setups)
                    {
                        setup.Configure(result);
                    }
                }
                return result;
            }
    
            public virtual TOptions Value
            {
                get
                {
                    return LazyInitializer.EnsureInitialized(
                        ref _options,
                        ref _cacheInitialized,
                        ref _cacheLock,
                        _createCache);
                }
            }
        }
    OptionsCache

    此处附录OptionsCache代码,里面(IConfigureOptions,ConfigureOptions)已经进行注入了。而ConfigureOptions代码如下:

        public class ConfigureOptions<TOptions> : IConfigureOptions<TOptions> where TOptions : class
        {
            public ConfigureOptions(Action<TOptions> action)
            {
                if (action == null)
                {
                    throw new ArgumentNullException(nameof(action));
                }
    
                Action = action;
            }
    
            public Action<TOptions> Action { get; private set; }
    
            public virtual void Configure(TOptions options)
            {
                if (options == null)
                {
                    throw new ArgumentNullException(nameof(options));
                }
    
                Action.Invoke(options);
            }
        }
    ConfigureOptions

    而ConfigureOptions实际上只是对Action<TOptions>的封装吧了(这里是不是可以理解为适配器)。

    *为什么要传递Action<T>进行配置?我的理解是因为延时性延时的概念就是,你做的修改不是立马生效,以至于配置的时候,我们都不用考虑先后顺序。

    OptionsMonitor部分

    OptionsMonitor是对Options的监视器。我决定这部分好像一个调度者模式??

    IOptionsChangeTokenSource

    OptionsMonitor代码如下:

        public class OptionsMonitor<TOptions> : IOptionsMonitor<TOptions> where TOptions : class, new()
        {
            private OptionsCache<TOptions> _optionsCache;
            private readonly IEnumerable<IConfigureOptions<TOptions>> _setups;
            private readonly IEnumerable<IOptionsChangeTokenSource<TOptions>> _sources;
    
            public OptionsMonitor(IEnumerable<IConfigureOptions<TOptions>> setups, IEnumerable<IOptionsChangeTokenSource<TOptions>> sources)
            {
                _sources = sources;
                _setups = setups;
                _optionsCache = new OptionsCache<TOptions>(setups);
            }
    
            public TOptions CurrentValue
            {
                get
                {
                    return _optionsCache.Value;
                }
            }
    
            public IDisposable OnChange(Action<TOptions> listener)
            {
                var disposable = new ChangeTrackerDisposable();
                foreach (var source in _sources)
                {
    
                    Action<object> callback = null;
                    IDisposable previousSubscription = null;
                    callback = (s) =>
                    {
                        // The order here is important. We need to take the token and then apply our changes BEFORE
                        // registering. This prevents us from possible having two change updates to process concurrently.
                        //
                        // If the token changes after we take the token, then we'll process the update immediately upon
                        // registering the callback.
                        var token = source.GetChangeToken();
    
                        // Recompute the options before calling the watchers
                        _optionsCache = new OptionsCache<TOptions>(_setups);
                        listener(_optionsCache.Value);
    
                        // Remove the old callback after its been fired
                        var nextSubscription = token.RegisterChangeCallback(callback, s);
                        disposable.Disposables.Add(nextSubscription);
                        disposable.Disposables.Remove(previousSubscription);
                        previousSubscription = nextSubscription;
                    };
    
                    previousSubscription = source.GetChangeToken().RegisterChangeCallback(callback, state: null);
                    disposable.Disposables.Add(previousSubscription);
                }
                return disposable;
            }
        }
    OptionsMonitor

    通过IOptionsChangeTokenSource的IChangeToken对象发出更改请求,之后Action<TOptions> listener进行数据更改。

    Onchange方法,实现上就是每次调用都会创建一个新的IDisposable(ChangeTrackerDisposable),如此而已。

  • 相关阅读:
    JPA常见坑
    IDEA的快捷键使用
    java注解
    @ResponseBody注解之返回json
    mybatis坑之Integer值为null
    Java后端之SQL语句
    SSM项目配置swaggerUI
    mybatis入门案例2
    mybatis入门案例
    部署本地服务器的前端及后端
  • 原文地址:https://www.cnblogs.com/watermoon2/p/5119085.html
Copyright © 2020-2023  润新知