ASP.NET Core 2.1 源码学习之 Options[3]:IOptionsMonitor 【转】
原文链接:https://www.cnblogs.com/RainingNight/p/strongly-typed-options-ioptions-monitor-in-asp-net-core.html
前面我们讲到 IOptions 和 IOptionsSnapshot,他们两个最大的区别便是前者注册的是单例模式,后者注册的是 Scope 模式。而 IOptionsMonitor 则要求配置源必须是可监听的,用来实现 Options 实例的自动更新,并对外提供了 OnChage 事件,给我们更多的控制权。
目录
- IOptionsMonitor
- OptionsMonitor源码探索
- ConfigurationChangeTokenSource
- 示例
IOptionsMonitor
对于 IOptionsMonitor 我们接触的较少,它的定义如下:
public interface IOptionsMonitor<out TOptions>
{
TOptions CurrentValue { get; }
TOptions Get(string name);
IDisposable OnChange(Action<TOptions, string> listener);
}
在AddOptions
扩展方法中,可以看到它的默认实现为 OptionsMonitor:
public static IServiceCollection AddOptions(this IServiceCollection services)
{
services.TryAdd(ServiceDescriptor.Singleton(typeof(IOptionsMonitor<>), typeof(OptionsMonitor<>)));
services.TryAdd(ServiceDescriptor.Transient(typeof(IOptionsFactory<>), typeof(OptionsFactory<>)));
services.TryAdd(ServiceDescriptor.Singleton(typeof(IOptionsMonitorCache<>), typeof(OptionsCache<>)));
}
OptionsMonitor源码探索
OptionsMonitor通过IOptionsChangeTokenSource
来实现事件的监听,具体如下:
public class OptionsMonitor<TOptions> : IOptionsMonitor<TOptions> where TOptions : class, new()
{
private readonly IOptionsMonitorCache<TOptions> _cache;
private readonly IOptionsFactory<TOptions> _factory;
private readonly IEnumerable<IOptionsChangeTokenSource<TOptions>> _sources;
internal event Action<TOptions, string> _onChange;
public OptionsMonitor(IOptionsFactory<TOptions> factory, IEnumerable<IOptionsChangeTokenSource<TOptions>> sources, IOptionsMonitorCache<TOptions> cache)
{
_factory = factory;
_sources = sources;
_cache = cache;
foreach (var source in _sources)
{
ChangeToken.OnChange<string>(() => source.GetChangeToken(), (name) => InvokeChanged(name), source.Name);
}
}
public TOptions CurrentValue => Get(Options.DefaultName);
public virtual TOptions Get(string name)
{
name = name ?? Options.DefaultName;
return _cache.GetOrAdd(name, () => _factory.Create(name));
}
public IDisposable OnChange(Action<TOptions, string> listener)
{
...
}
private void InvokeChanged(string name)
{
...
}
}
首先看构造函数中的三个参数,其中 IOptionsFactory<>
在上一章已讲过,而IOptionsChangeTokenSource
则在 第一章 中介绍过,通过IConfiguration
进行配置的 Options,会注册该类型的实现,用来实现对配置源的监听:
public static IServiceCollection Configure<TOptions>(this IServiceCollection services, string name, IConfiguration config) where TOptions : class
{
...
services.AddSingleton<IOptionsChangeTokenSource<TOptions>>(new ConfigurationChangeTokenSource<TOptions>(name, config));
...
}
IOptionsChangeTokenSource 的定义如下:
public interface IOptionsChangeTokenSource<out TOptions>
{
IChangeToken GetChangeToken();
string Name { get; }
}
在OptionsMonitor
的构造函数中,通过调用其GetChangeToken
方法,获取到 ChangeToken ,在 InvokeChanged
完成 *_onChange* 事件的调用:
private void InvokeChanged(string name)
{
name = name ?? Options.DefaultName;
_cache.TryRemove(name);
var options = Get(name);
if (_onChange != null)
{
_onChange.Invoke(options, name);
}
}
而对外暴露的OnChange
方法,方便我们注册自己的逻辑:
public IDisposable OnChange(Action<TOptions> listener)
{
var disposable = new ChangeTrackerDisposable(this, listener);
_onChange += disposable.OnChange;
return disposable;
}
这里又使用了一个 ChangeTrackerDisposable 的包装类,用来实现事件的注销:
internal class ChangeTrackerDisposable : IDisposable
{
private readonly Action<TOptions> _listener;
private readonly OptionsMonitor<TOptions> _monitor;
public ChangeTrackerDisposable(OptionsMonitor<TOptions> monitor, Action<TOptions> listener)
{
_listener = listener;
_monitor = monitor;
}
public void OnChange(TOptions options) => _listener.Invoke(options);
public void Dispose() => _monitor._onChange -= OnChange;
}
构造函数的最后一个参数IOptionsMonitorCache
的默认实现便是 上一章 中介绍的 OptionsCache
。
ConfigurationChangeTokenSource
IConfigurationChangeTokenSource 的默认实现类是 ConfigurationChangeTokenSource
:
public class ConfigurationChangeTokenSource<TOptions> : IOptionsChangeTokenSource<TOptions>
{
private IConfiguration _config;
public ConfigurationChangeTokenSource(IConfiguration config) : this(Options.DefaultName, config) { }
public ConfigurationChangeTokenSource(string name, IConfiguration config)
{
if (config == null)
{
throw new ArgumentNullException(nameof(config));
}
_config = config;
}
public string Name { get; }
public IChangeToken GetChangeToken()
{
return _config.GetReloadToken();
}
}
上面用到的 ChangeToken 便是通过构造函数接受的IConfiguration
类型的参数来获取的:
public interface IConfiguration
{
...
IChangeToken GetReloadToken();
...
}
因此要想使用IOptionsMonitor
,通常要使用IConfiguration
来注册才可以,当然,你也可以实现自己的 ConfigurationChangeTokenSource
。
示例
下面简单演示一下IOptionsMonitor
的使用:
首先创建一个控制台程序,添加appsettings.json
:
{
"Name": "bob"
}
然后修改Program.cs
如下:
public class MyOptions
{
public string Name { get; set; }
}
class Program
{
private IOptionsMonitor<MyOptions> _options;
public Program()
{
var configuration = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
.Build();
var serviceCollection = new ServiceCollection();
serviceCollection.Configure<MyOptions>(configuration);
var serviceProvider = serviceCollection.BuildServiceProvider();
_options = serviceProvider.GetRequiredService<IOptionsMonitor<MyOptions>>();
}
public static void Main(string[] args)
{
new Program().Execute(args);
}
public void Execute(string[] args)
{
Console.WriteLine(_options.CurrentValue.Name);
_options.OnChange(_ => Console.WriteLine(_.Name));
Console.ReadKey();
}
}
我们手动修改配置文件,便会触发OnChange事件。
附示例代码地址:https://github.com/RainingNight/AspNetCoreSample/tree/master/src/OptionsSample 。
总结
本章介绍了 IOptionsMonitor
的实现:通过 IConfiguration 所提供的 ChangeToken
,来注册监听事件,对其 CurrentValue
进行更新。到此,ASP.NET Core 中的 Options 源码也就分析完了,其本身比较简单,并没有太多东西。更具体的可以去 Github 上看完整的源码。
ASP.NET Core 2.1 源码学习之 Options[3]:IOptionsMonitor 【转】的更多相关文章
- ASP.NET Core 2.1 源码学习之 Options[3]:IOptionsMonitor
前面我们讲到 IOptions 和 IOptionsSnapshot,他们两个最大的区别便是前者注册的是单例模式,后者注册的是 Scope 模式.而 IOptionsMonitor 则要求配置源必须是 ...
- ASP.NET Core 2.1 源码学习之 Options[1]:Configure
配置的本质就是字符串的键值对,但是对于面向对象语言来说,能使用强类型的配置是何等的爽哉! 目录 ASP.NET Core 配置系统 强类型的 Options Configure 方法 Configur ...
- ASP.NET Core 2.1 源码学习之 Options[1]:Configure 【转】
原文链接:https://www.cnblogs.com/RainingNight/p/strongly-typed-options-configure-in-asp-net-core.html 配置 ...
- ASP.NET Core 2.1 源码学习之 Options[2]:IOptions
在 上一章 中,介绍了Options的注册,而在使用时只需要注入 IOption<T> 即可: public ValuesController(IOptions<MyOptions& ...
- ASP.NET Core 2.1 源码学习之 Options[2]:IOptions 【转】
原文链接:https://www.cnblogs.com/RainingNight/p/strongly-typed-options-ioptions-in-asp-net-core.html 在 上 ...
- ASP.NET Core 源码学习之 Options[4]:IOptionsMonitor
前面我们讲到 IOptions 和 IOptionsSnapshot,他们两个最大的区别便是前者注册的是单例模式,后者注册的是 Scope 模式.而 IOptionsMonitor 则要求配置源必须是 ...
- ASP.NET Core 选项模式源码学习Options Configure(一)
前言 ASP.NET Core 后我们的配置变得更加轻量级了,在ASP.NET Core中,配置模型得到了显著的扩展和增强,应用程序配置可以存储在多环境变量配置中,appsettings.json用户 ...
- ASP.NET Core 选项模式源码学习Options IOptions(二)
前言 上一篇文章介绍IOptions的注册,本章我们继续往下看 IOptions IOptions是一个接口里面只有一个Values属性,该接口通过OptionsManager实现 public in ...
- ASP.NET Core 选项模式源码学习Options IOptionsMonitor(三)
前言 IOptionsMonitor 是一种单一示例服务,可随时检索当前选项值,这在单一实例依赖项中尤其有用.IOptionsMonitor用于检索选项并管理TOption实例的选项通知, IOpti ...
随机推荐
- 进程、内存的理想与现实 VS 虚拟内存
理想情况下一个进程的运行,需要一块足够大的连续的内存进行装载. 现状: 1)内存不够大:分解进程内存空间. 2)内存不连续:内存映射.
- C++11 新特性之 decltypekeyword
版权声明:本文为博主原创文章,未经博主同意不得转载. https://blog.csdn.net/lr982330245/article/details/30728131 decltypekeywor ...
- python 面向对象(四)--实例属性和类属性
由于Python是动态语言,根据类创建的实例可以任意绑定属性. 给实例绑定属性的方法是通过实例变量,或者通过self变量: class Student(object): def __init__(se ...
- MapReduce计算每年最大值测试样例生成程序
Demo.java package com.java; import java.io.BufferedWriter; import java.io.File; import java.io.FileW ...
- Vuex基础-Mutation
借助官网的一张图,更改 Vuex 的 store 中的状态的唯一方法是提交 mutation.不可以直接对其进行赋值改变.需要注意的是,mutations只能做一些同步的操作. 代码结构: ...
- JAVAWEB开发中过滤器的概述及使用
1.什么是过滤器? 过滤器是向WEB应用程序的请求和响应添加功能的WEB服务组件 2.过滤器的作用 1)可以统一的集中处理请求和响应 2)可以实现对请求数据的过滤 3.过滤器的工作方式 4.使用场合 ...
- Java基础-方法区以及static的内存分配图
转载自: https://blog.csdn.net/Wang_1997/article/details/52267688 前面的几篇都没有太明确地指出 方法区 是什么?现在通过一些资料的收集和学习, ...
- Q&A - Apache、Nginx与Tomcat的区别?
一. 定义: 1. Apache Apache HTTP服务器是一个模块化的服务器,可以运行在几乎所有广泛使用的计算机平台上.其属于应用服务器.Apache支持支持模块多,性能稳定,A ...
- $.each() 循环遍历完后阻止再执行的办法
jquery each循环遍历完再执行的方法 因为each是异步的 所以要加计数器. query each循环遍历完再执行的方法 因为each是异步的 所以要加计数器.var eachcount=0; ...
- 交换机基础配置之结合以太通道的vlan设置
我们将以上面的拓扑图来做实验,建立以太通道,并设置好vlan,将pc1和pc3放在同一vlan,将pc2和pc4放在同一vlan,同一vlan能跨交换机通信 在一切还没布置之前,四台pc机都在同一网段 ...