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
.