IChangeToken监控配置文件修改
Configuration是支持监控配置文件修改的,如果设置了ReloadOnChange=true,则当配置文件发生改变时,会自动重新加载,这是通过IChangeToken实现的。
文件类型的配置文件提供程序都继承自虚基类FileConfigurationProvider,配置源继承自FileConfigurationSource。FileConfigurationSource中的ReloadOnChange属性,配置是否监控文件的修改。当该属性置为true时,在Provider中会通过ChangeToken.OnChange()方法订阅配置文件更改事件,当发生修改时重新加载文件。代码如下:
if (Source.ReloadOnChange && Source.FileProvider != null)
{
_changeTokenRegistration = ChangeToken.OnChange(
() => Source.FileProvider.Watch(Source.Path),
() =>
{
Thread.Sleep(Source.ReloadDelay);
Load(reload: true);
});
}
先看下ChangeToken.OnChange()方法,该方法提供了生产者-消费者模式。生产者为创建IChangeToken的工厂,IChangeToken有一个RegisterChangeCallback方法注册回调函数。在ChangeTokenRegistration的构造函数中,会调用IChangeToken.RegisterChangeCallback()将消费者注册为回调函数,这样即实现了生产-消费模式。
public static IDisposable OnChange<TState>(Func<IChangeToken?> changeTokenProducer,
Action<TState> changeTokenConsumer, TState state)
{
if (changeTokenProducer == null)
throw new ArgumentNullException(nameof(changeTokenProducer));
if (changeTokenConsumer == null)
throw new ArgumentNullException(nameof(changeTokenConsumer));
return new ChangeTokenRegistration<TState>(changeTokenProducer, changeTokenConsumer, state);
}
public interface IChangeToken
{
bool HasChanged { get; }
bool ActiveChangeCallbacks { get; }
IDisposable RegisterChangeCallback(Action<object?> callback, object? state);
}
回到文件监控上,FileProvider.Watch()方法返回一个CancellationChangeToken。当CancellationTokenSource调用Cancel()方法时(使用了FileSystemWatcher,监听其Changed事件,当事件触发时调用Cancel()方法),就会触发回调,Load()方法便会重新加载配置文件,从而实现配置文件的修改监控。
Load方法还会继续向上传递文件修改信息。ConfigurationProvider、ConfigurationRoot、ConfigurationManager均有一个ConfigurationReloadToken字段,用来监控修改。ConfigurationReloadToken与CancellationChangeToken一样,都是使用CancellationTokenSource实现的消费回调。当调用Load方法时,也会触发ConfigurationProvider的回调。
public class ConfigurationReloadToken : IChangeToken
{
private CancellationTokenSource _cts = new CancellationTokenSource();
public bool ActiveChangeCallbacks => true;
public bool HasChanged => _cts.IsCancellationRequested;
public IDisposable RegisterChangeCallback(Action<object?> callback, object? state) =>
_cts.Token.Register(callback, state);
public void OnReload() => _cts.Cancel();
}
// FileConfigurationProvider
private void Load(bool reload)
{
// ...
OnReload();
}
// ConfigurationProvider
protected void OnReload()
{
ConfigurationReloadToken previousToken = Interlocked.Exchange(ref _reloadToken,
new ConfigurationReloadToken());
previousToken.OnReload();
}
ConfigurationProvider的IChangeToken又会触发ConfigurationRoot、ConfigurationManager的回调,从而实现向上传递。
// ConfigurationRoot构造函数
public ConfigurationRoot(IList<IConfigurationProvider> providers)
{
if (providers == null)
throw new ArgumentNullException(nameof(providers));
_providers = providers;
_changeTokenRegistrations = new List<IDisposable>(providers.Count);
foreach (IConfigurationProvider p in providers)
{
p.Load();
_changeTokenRegistrations.Add(ChangeToken.OnChange(() => p.GetReloadToken(), () => RaiseChanged()));
}
}
private void RaiseChanged()
{
ConfigurationReloadToken previousToken = Interlocked.Exchange(ref _changeToken,
new ConfigurationReloadToken());
previousToken.OnReload();
}
程序中可以通过ChangeToken.OnChange()方法绑定IConfiguration的IChangeToken,订阅配置文件的修改事件。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?