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


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<>接口對象就可以讀取到更新之后的配置信息了


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM