基于选项模式实现.NET Core的配置热更新( 四 )


public class ConfigurationRoot : IConfigurationRoot{ private ConfigurationReloadToken _changeToken = new ConfigurationReloadToken; private IList _providers; public ConfigurationRoot(IList providers) { _providers = providers; foreach (var provider in providers) { provider.Load; ChangeToken.OnChange( => provider.GetReloadToken, this.RaiseChanged); } } public IChangeToken GetReloadToken => return _changeToken; private void RaiseChanged { Interlocked.Exchange(ref _changeToken, new ConfigurationReloadToken).OnReload; } public void Reload { foreach (var provider in _providers) { provider.Load; } this.RaiseChanged; } }
基于选项模式实现.NET Core的配置热更新文章插图
自定义配置源好了 , 现在你可以说你了解 .NET Core 的配置热更新这个话题了 , 因为截至到此时此刻 , 我们不仅仅达到了一开始的目的 , 而且深刻地理解了它背后蕴含的原理 。 这样 , 我们就可以向着下一个目标:自定义配置源努力了 。 前面提到过 , .NET Core 里面支持各种各样的配置源 , 实际中可能会遇到更多的配置源 , 比如不同的数据库、YAML 格式以及 Apollo、Consul、Nacos 这些配置中心等等 , 所以 , 了解如何去写一个自定义的配置源还是非常有必要的 。 我们在一开始的时候提到了 Redis 的发布-订阅 , 那么 , 下面我们就来基于发布-订阅实现一个简单的配置中心 , 当我们需要修改配置时 , 只需要通过可视化的 Redis 工具进行修改 , 然后再给指定的客户端发一条消息即可 。
实现自定义配置源 , 需要实现 IConfigurationSource 和IConfigurationProvider 两个接口 , 前者实现起来非常简单 , 因为只要返回我们定义的RedisConfigurationProvider 实例即可:
public class RedisConfigurationSource : IConfigurationSource{ private readonly RedisConfigurationOptions _options; public RedisConfigurationSource(RedisConfigurationOptions options) { _options = options; } public IConfigurationProvider Build(IConfigurationBuilder builder) { return new RedisConfigurationProvider(_options); }}接下来是 RedisConfigurationProvider 类的实现:
public class RedisConfigurationProvider : ConfigurationProvider{ private CSRedisClient _redisClient; private readonly RedisConfigurationOptions _options; public RedisConfigurationProvider(RedisConfigurationOptions options ) { _options = options; _redisClient = new CSRedisClient(_options.ConnectionString); if (options.AutoReload) { //利用Redis的发布-订阅重新加载配置 _redisClient.Subscribe((_options.HashCacheChannel, msg => Load)); } } public override void Load { Data = http://kandian.youth.cn/index/_redisClient.HGetAll(_options.HashCacheKey) ?? new Dictionary; }}为了用起来更得心应手 , 扩展方法是少不了的:
public class RedisConfigurationProvider : ConfigurationProvider{ private CSRedisClient _redisClient; private readonly RedisConfigurationOptions _options; public RedisConfigurationProvider(RedisConfigurationOptions options ) { _options = options; _redisClient = new CSRedisClient(_options.ConnectionString); if (options.AutoReload) { //利用Redis的发布-订阅重新加载配置 _redisClient.Subscribe((_options.HashCacheChannel, msg => Load)); } } public override void Load { Data = http://kandian.youth.cn/index/_redisClient.HGetAll(_options.HashCacheKey) ?? new Dictionary; }}现在 , 我们改一下入口类 Program.cs , 因为在这个阶段依赖注入是无法使用的 , 所以 , 看起来有一点难受 , 从命名就可以看出来 , 内部使用了Hash 这种结构 , 理论上每个客户端应该使用不同的 Key 来进行缓存 , 应该使用不同的 Channel 来接收配置更新的通知:
public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) .ConfigureAppConfiguration(configurationBuilder =>