前言

IOptionsMonitor 是一种单一示例服务,可随时检索当前选项值,这在单一实例依赖项中尤其有用。IOptionsMonitor用于检索选项并管理TOption实例的选项通知, IOptionsMonitor 支持以下方案:

  • 更改通知
  • 命名选项
  • 可重载配置
  • 选择性选项失效 (IOptionsMonitorCache)

IOptionsMonitor


public interface IOptionsMonitor<out TOptions>
{
/// <summary>
/// 返回具有 DefaultName 的当前 TOptions 实例。
/// </summary>
TOptions CurrentValue { get; } /// <summary>
/// 返回具有给定名称的已配置的 TOptions 实例。
/// </summary>
TOptions Get(string name); /// <summary>
/// 注册一个要在命名 TOptions 更改时调用的侦听器。
/// </summary>
IDisposable OnChange(Action<TOptions, string> listener);
}

OptionsMonitor

OptionsMonitor通过IOptionsChangeTokenSource实现监听事件

    public class OptionsMonitor<TOptions> : IOptionsMonitor<TOptions>, IDisposable where TOptions : class, new()
{
private readonly IOptionsMonitorCache<TOptions> _cache;
private readonly IOptionsFactory<TOptions> _factory;
private readonly IEnumerable<IOptionsChangeTokenSource<TOptions>> _sources;
private readonly List<IDisposable> _registrations = new List<IDisposable>();
internal event Action<TOptions, string> _onChange; /// <summary>
/// Constructor.
/// </summary>
/// <param name="factory">The factory to use to create options.</param>
/// <param name="sources">The sources used to listen for changes to the options instance.</param>
/// <param name="cache">The cache used to store options.</param>
public OptionsMonitor(IOptionsFactory<TOptions> factory, IEnumerable<IOptionsChangeTokenSource<TOptions>> sources, IOptionsMonitorCache<TOptions> cache)
{
_factory = factory;
_sources = sources;
_cache = cache; foreach (var source in _sources)
{
var registration = ChangeToken.OnChange(
() => source.GetChangeToken(),
(name) => InvokeChanged(name),
source.Name); _registrations.Add(registration);
}
} private void InvokeChanged(string name)
{
name = name ?? Options.DefaultName;
_cache.TryRemove(name);
var options = Get(name);
if (_onChange != null)
{
_onChange.Invoke(options, name);
}
} /// <summary>
/// The present value of the options.
/// </summary>
public TOptions CurrentValue
{
get => Get(Options.DefaultName);
} /// <summary>
/// Returns a configured <typeparamref name="TOptions"/> instance with the given <paramref name="name"/>.
/// </summary>
public virtual TOptions Get(string name)
{
name = name ?? Options.DefaultName;
return _cache.GetOrAdd(name, () => _factory.Create(name));
} /// <summary>
/// Registers a listener to be called whenever <typeparamref name="TOptions"/> changes.
/// </summary>
/// <param name="listener">The action to be invoked when <typeparamref name="TOptions"/> has changed.</param>
/// <returns>An <see cref="IDisposable"/> which should be disposed to stop listening for changes.</returns>
public IDisposable OnChange(Action<TOptions, string> listener)
{
var disposable = new ChangeTrackerDisposable(this, listener);
_onChange += disposable.OnChange;
return disposable;
} /// <summary>
/// Removes all change registration subscriptions.
/// </summary>
public void Dispose()
{
// Remove all subscriptions to the change tokens
foreach (var registration in _registrations)
{
registration.Dispose();
}
_registrations.Clear();
} internal class ChangeTrackerDisposable : IDisposable
{
private readonly Action<TOptions, string> _listener;
private readonly OptionsMonitor<TOptions> _monitor; public ChangeTrackerDisposable(OptionsMonitor<TOptions> monitor, Action<TOptions, string> listener)
{
_listener = listener;
_monitor = monitor;
} public void OnChange(TOptions options, string name) => _listener.Invoke(options, name); public void Dispose() => _monitor._onChange -= OnChange;
}
}

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, string> listener)
{
var disposable = new ChangeTrackerDisposable(this, listener);
_onChange += disposable.OnChange;
return disposable;
}

通过ChangeTrackerDisposable进行事件的注销


internal class ChangeTrackerDisposable : IDisposable
{
private readonly Action<TOptions, string> _listener;
private readonly OptionsMonitor<TOptions> _monitor; public ChangeTrackerDisposable(OptionsMonitor<TOptions> monitor, Action<TOptions, string> listener)
{
_listener = listener;
_monitor = monitor;
} public void OnChange(TOptions options, string name) => _listener.Invoke(options, name); public void Dispose() => _monitor._onChange -= OnChange;
}

ConfigurationChangeTokenSource

ConfigurationChangeTokenSource实现IOptionsChangeTokenSource接口


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;
Name = name ?? Options.DefaultName;
} public string Name { get; } public IChangeToken GetChangeToken()
{
return _config.GetReloadToken();
}
}

示例


public class WeatherForecastController : ControllerBase
{
private readonly ILogger<WeatherForecastController> _logger; private readonly IOptionsMonitor<MyOptions> _options;
public WeatherForecastController(IOptionsMonitor<MyOptions> options, ILogger<WeatherForecastController> logger)
{
_options = options;
_logger = logger;
} [HttpGet]
public OkObjectResult Get() {
_options.OnChange(_=>_logger.LogWarning(_options.CurrentValue.Name));
return Ok(string.Format("Name:{0},Url:{1}", _options.CurrentValue.Name,_options.CurrentValue.Url));
}
}

现在我们每次修改配置文件,便会触发OnChange事件

ASP.NET Core 选项模式源码学习Options IOptionsMonitor(三)的更多相关文章

  1. ASP.NET Core 选项模式源码学习Options Configure(一)

    前言 ASP.NET Core 后我们的配置变得更加轻量级了,在ASP.NET Core中,配置模型得到了显著的扩展和增强,应用程序配置可以存储在多环境变量配置中,appsettings.json用户 ...

  2. ASP.NET Core 选项模式源码学习Options IOptions(二)

    前言 上一篇文章介绍IOptions的注册,本章我们继续往下看 IOptions IOptions是一个接口里面只有一个Values属性,该接口通过OptionsManager实现 public in ...

  3. ASP.NET Core 2.1 源码学习之 Options[1]:Configure

    配置的本质就是字符串的键值对,但是对于面向对象语言来说,能使用强类型的配置是何等的爽哉! 目录 ASP.NET Core 配置系统 强类型的 Options Configure 方法 Configur ...

  4. ASP.NET Core 2.1 源码学习之 Options[3]:IOptionsMonitor

    前面我们讲到 IOptions 和 IOptionsSnapshot,他们两个最大的区别便是前者注册的是单例模式,后者注册的是 Scope 模式.而 IOptionsMonitor 则要求配置源必须是 ...

  5. ASP.NET Core 2.1 源码学习之 Options[3]:IOptionsMonitor 【转】

    原文链接:https://www.cnblogs.com/RainingNight/p/strongly-typed-options-ioptions-monitor-in-asp-net-core. ...

  6. ASP.NET Core 2.1 源码学习之 Options[1]:Configure 【转】

    原文链接:https://www.cnblogs.com/RainingNight/p/strongly-typed-options-configure-in-asp-net-core.html 配置 ...

  7. ASP.NET Core 2.1 源码学习之 Options[2]:IOptions

    在 上一章 中,介绍了Options的注册,而在使用时只需要注入 IOption<T> 即可: public ValuesController(IOptions<MyOptions& ...

  8. ASP.NET Core 2.1 源码学习之 Options[2]:IOptions 【转】

    原文链接:https://www.cnblogs.com/RainingNight/p/strongly-typed-options-ioptions-in-asp-net-core.html 在 上 ...

  9. .NET Core 2.1 源码学习:看 SocketsHttpHandler 如何在异步方法中连接 Socket

    在 .NET Core 2.1 中,System.Net.Sockets 的性能有了很大的提升,最好的证明是 Kestrel 与 HttpClient 都改为使用 System.Net.Sockets ...

随机推荐

  1. Download-学习资源下载

    小白求关爱:链接为本人工作中学习所碰到的,如有不对之处,请及时联系加以改正,后续仍会追加新链接地址并及时更新旧链接地址 Jdk历史版本 https://www.oracle.com/technetwo ...

  2. PHP 面试官问:你说说Redis的几个过期策略?

    在使用redis时,一般会设置一个过期时间,当然也有不设置过期时间的,也就是永久不过期.当设置了过期时间,redis是如何判断是否过期,以及根据什么策略来进行删除的. 设置过期时间 expire ke ...

  3. 一文带你深入了解 redis 复制技术及主从架构

    主从架构可以说是互联网必备的架构了,第一是为了保证服务的高可用,第二是为了实现读写分离,你可能熟悉我们常用的 MySQL 数据库的主从架构,对于我们 redis 来说也不意外,redis 数据库也有各 ...

  4. 推荐收藏系列:一文理解JVM虚拟机(内存、垃圾回收、性能优化)解决面试中遇到问题(图解版)

    欢迎一起学习 <提升能力,涨薪可待篇> <面试知识,工作可待篇 > <实战演练,拒绝996篇 > 欢迎关注我博客 也欢迎关注公 众 号[Ccww笔记],原创技术文章 ...

  5. axios 请求二次封装

    /** * 封装get方法 * @param url * @param data * @returns {Promise} */ export function get(url, params) { ...

  6. UCloud 云服务内容审核 Java 版本实现

    前言 最近不少小伙伴反映上传小黄图偶尔性的异常,并且不能上传动态图片,很是苦恼!无她,鉴黄API还没有这么智能,毕竟是自己训练的,不是那么专业!为了更好的服务广大网友,撸主决定接入更加智能快速的鉴黄服 ...

  7. 新闻实时分析系统 基于IDEA环境下的Spark2.X程序开发

    1.Windows开发环境配置与安装 下载IDEA并安装,可以百度一下免费文档. 2.IDEA Maven工程创建与配置 1)配置maven 2)新建Project项目 3)选择maven骨架 4)创 ...

  8. Java并发之synchronized关键字和Lock接口

    欢迎点赞阅读,一同学习交流,有疑问请留言 . GitHub上也有开源 JavaHouse,欢迎star 引用 当开发过程中,我们遇到并发问题.怎么解决? 一种解决方式,简单粗暴:上锁.将千军万马都给拦 ...

  9. 《浅入浅出》-RocketMQ

    你知道的越多,你不知道的越多 点赞再看,养成习惯 本文GitHub https://github.com/JavaFamily 已收录,有一线大厂面试点脑图.个人联系方式和技术交流群,欢迎Star和指 ...

  10. 封装一个适用于vue的 jsonp

    import originJsonp from 'jsonp' export default function jsonp(url, data, option) { return new Promis ...