Asp.Net Core 选项模式的三种注入方式

前言

记录下最近在成都的面试题, 选项模式的热更新, 没答上来

正文

选项模式的依赖注入共有三种接口, 分别是 IOptions<>, IOptionsSnapshot<>, IOptionsMonitor<>, 它们内部都实现了缓存,所以注入后除了第一次调用之外都是从缓存中直接取.
其中 IOptions<>, IOptionsMonitor<> 都注册成了单例, IOptionsSnapshot<> 注册成了作用域

services.TryAdd(ServiceDescriptor.Singleton(typeof(IOptions<>), typeof(OptionsManager<>)));
services.TryAdd(ServiceDescriptor.Scoped(typeof(IOptionsSnapshot<>), typeof(OptionsManager<>)));
services.TryAdd(ServiceDescriptor.Singleton(typeof(IOptionsMonitor<>), typeof(OptionsMonitor<>)));

IOptions<>

由于 IOptions<> 注册成了单例, 整个应用程序生命周期只会实例化一次, 选项值将会在第一次调用 .Value的时候加入缓存, 之后就不会再更新了

public interface IOptions<out TOptions> where TOptions : class
{
    TOptions Value { get; }
}

OptionsManager

public class OptionsManager<TOptions> : IOptions<TOptions>, IOptionsSnapshot<TOptions> where TOptions : class
{
    private readonly IOptionsFactory<TOptions> _factory;
    private readonly OptionsCache<TOptions> _cache = new OptionsCache<TOptions>();
    public OptionsManager(IOptionsFactory<TOptions> factory)
    {
        _factory = factory;
    }
    public TOptions Value
    {
        get
        {
            return Get(Options.DefaultName);
        }
    }
    public virtual TOptions Get(string name)
    {
        name = name ?? Options.DefaultName;
        return _cache.GetOrAdd(name, () => _factory.Create(name));
    }
}

IOptionsSnapshot<>

可以看到 IOptions<>IOptionsSnapshot<> 的实现类都是 OptionsManager, 它们之间的区别就在于生命周期不同, IOptionsSnapshot<> 是作用域的所以它将在每一次请求重新被实例化, 选项值将会被重新获取

public interface IOptionsSnapshot<out TOptions> : IOptions<TOptions> where TOptions : class
{
    TOptions Get(string name);
}

IOptionsMonitor<>

IOptionsMonitor<> 也是注册成单例的, 但是它会在选项改变时接收到通知, 从而更新缓存值, 使用者也可以注册监听器在选项变更后,做出对应的处理

public interface IOptionsMonitor<out TOptions>
{
    TOptions CurrentValue { get; }
    TOptions Get(string name);
    IDisposable OnChange(Action<TOptions, string> listener);
}

总结

不需要热更新选项的时候注入 IOptions<>, 需要热更新和选项变更通知的注入 IOptionsMonitor<>, 仅需要热更新的注入 IOptionsSnapshot<> 缺点是每一次请求都会重新实例化, 传统发布不能停机的选用这个.
当然热更新需要 reloadOnChange: True.

posted @ 2020-07-30 13:41  huiyuanai709  阅读(458)  评论(0编辑  收藏  举报