dotnetcore中的IOptionsSnapshot<>的自动更新原理

本文详细解析了C#中配置文件变更监听机制的具体实现方式,包括如何通过ChangeToken.OnChange方法来监听配置更改,以及IOptions和IOptionsSnapshot的生命周期管理等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、首先讲讲ChangeToken.OnChange方法:

原理是给一个CancellationToken注册一个消费者委托,调用CancellationToken的Cancel的时候会调用这个CancellationToken中所有的委托 代码实现如下:

public static IDisposable OnChange(Func<IChangeToken> changeTokenProducer, Action changeTokenConsumer)
{
    if (changeTokenProducer == null)
    {
        throw new ArgumentNullException("changeTokenProducer");
    }
    if (changeTokenConsumer == null)
    {
        throw new ArgumentNullException("changeTokenConsumer");
    }
    Action<object> callback = null;
    callback = delegate(object s)
    {
        IChangeToken changeToken = changeTokenProducer();
        try
        {
            changeTokenConsumer();
        }
        finally
        {
            changeToken.RegisterChangeCallback(callback, null);
        }
    };
    return changeTokenProducer().RegisterChangeCallback(callback, null);
}

 

2、IOptions<> 生命周期为Singleton,初始化的时候配置就已经存入缓存,并且不再更新
3、IOptionsSnapshot<> 生命周期为Scope,初始化的时候会写入缓存,内容由OptionsMonitor提供,初始化OptionsMonitor的时候会给所有的IOtionsChangeTokenSource<T>对象的ChangeToken注册一个重载配置的方法代码如下
using (IEnumerator<IOptionsChangeTokenSource<TOptions>> enumerator =  this._sources.GetEnumerator())
{
    while (enumerator.MoveNext())
    {
        IOptionsChangeTokenSource<TOptions> source = enumerator.Current;
        ChangeToken.OnChange(() => source.GetChangeToken(), delegate
        {
            this.InvokeChanged();
        });
    }
}

这里的source.GetChangeToken中的Token是从IConfigurationRoot中获取的,以下代码可以证明:

public class ConfigurationChangeTokenSource<TOptions> : IOptionsChangeTokenSource<TOptions>
    {
        private IConfiguration _config;

        /// <summary>
        /// Constructor taking the IConfiguration instance to watch.
        /// </summary>
        /// <param name="config">The configuration instance.</param>
        public ConfigurationChangeTokenSource(IConfiguration config)
        {
            if (config == null)
            {
                throw new ArgumentNullException("config");
            }
            this._config = config;
        }

        /// <summary>
        /// Returns the reloadToken from IConfiguration.
        /// </summary>
        /// <returns></returns>
        public IChangeToken GetChangeToken()
        {
            return this._config.GetReloadToken();
        }
    }

这里的_config就是调用AddOptions.Config(...)方法的时候注册进去的,而ConfigurationRoot在初始化的时候,会把自己的ChangeToken的Reload事件注册到所有的IConfigurationProvider对象的ChangeToken,代码如下

public ConfigurationRoot(IList<IConfigurationProvider> providers)
{
    if (providers == null)
    {
        throw new ArgumentNullException("providers");
    }
    this._providers = providers;
    using (IEnumerator<IConfigurationProvider> enumerator = providers.GetEnumerator())
    {
        while (enumerator.MoveNext())
        {
            IConfigurationProvider p = enumerator.Current;
            p.Load();
            ChangeToken.OnChange(() => p.GetReloadToken(), delegate
            {
                this.RaiseChanged();
            });
        }
    }
}
private void RaiseChanged()
{
    //执行自身的_changeToken的OnReload事件并且重新初始化一个ConfigurationReloadToken
    Interlocked.Exchange<ConfigurationReloadToken>(ref this._changeToken, new ConfigurationReloadToken()).OnReload();
}

这样就可以保证所有的ConfigurationProvider发生Reload的时候,IConfigurationRoot中的ChangeToken也会发生Reload事件。而我们的配置发生改变的时候,我们的ConfigurationProvider需要先更新Data数据,然后再触发他的Reload事件,就可以触发IConfigurationRoot的Reload事件,OptionsMonitor初始化的时候会给IConfigurationRoot的ChangeToken注册一个更新配置缓存的事件(前面说到过),所以OptionsMonitor就会更新配置缓存,然后下一次请求的时候创建的新IOptionsSnapshot<>接口对象就可以读取到更新之后的配置信息了

转载于:https://www.cnblogs.com/dingsblog/p/6761804.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值