• .NET Core开发实战(第16课:选项数据热更新:让服务感知配置的变化)--学习笔记


    16 | 选项数据热更新:让服务感知配置的变化

    选项框架还有两个关键类型:

    1、IOptionsMonitor

    2、IOptionsSnapshot

    场景:

    1、范围作用域类型使用 IOptinsSnapshot

    2、单例服务使用 IOptionsMonitor

    通过代码更新选项:

    IPostConfigureOptions

    延续上一节的代码,但是做一些特殊处理,之前注册 Order 服务用的是单例模式,这里改为 Scoped 模式

    public void ConfigureServices(IServiceCollection services)
    {
        services.Configure<OrderServiceOptions>(Configuration.GetSection("OrderService"));
        //services.AddSingleton<IOrderService, OrderService>();
        services.AddScoped<IOrderService, OrderService>();
        services.AddControllers();
    }
    

    service 还是使用 IOptions

    public class OrderService : IOrderService
    {
        IOptions<OrderServiceOptions> _options;
        
        public OrderService(IOptions<OrderServiceOptions> options)
        {
            _options = options;
        }
    
        public int ShowMaxOrderCount()
        {
            return _options.Value.MaxOrderCount;
        }
    }
    

    启动程序,输出如下:

    orderService.ShowMaxOrderCount:200
    

    修改配置

    {
        "OrderService": {
        "MaxOrderCount": 2000
      }
    }
    

    启动程序,输出如下:

    orderService.ShowMaxOrderCount:200
    

    输出值还是200

    那么如何能够读到新的配置呢?

    只需要把 IOptions 换成 IOptionsSnapshot 即可

    IOptionsSnapshot<OrderServiceOptions> _options;
    
    public OrderService(IOptionsSnapshot<OrderServiceOptions> options)
    {
        ...
    }
    

    这是因为我们的服务注册的是 Scoped 模式,并且使用 Snapshot 来读取配置,每次请求都会重新计算并读取配置

    那如果我们的服务是单例的时候怎么办呢?

    把服务注册改为单例模式

    services.AddSingleton<IOrderService, OrderService>();
    

    这里需要使用另一个接口,把 Snapshot 改为 Monitor

    IOptionsMonitor<OrderServiceOptions> _options;
    
    public OrderService(IOptionsMonitor<OrderServiceOptions> options)
    {
        ...
    }
    

    Monitor 与 Snapshot 的定义略微有些不同,它获取值是需要用 CurrentValue 字段

    public int ShowMaxOrderCount()
    {
        return _options.CurrentValue.MaxOrderCount;
    }
    

    启动程序,修改配置文件,刷新浏览器,可以看到输出了修改后的数据,也就是说单例对象同时也能读取到最新的配置

    如果说我想知道配置的值发生变化并且通知到我的 Options 怎么做呢?

    首先看一下 Monitor 的定义

    namespace Microsoft.Extensions.Options
    {
      public interface IOptionsMonitor<out TOptions>
      {
    
        TOptions CurrentValue { get; }
    
        TOptions Get(string name);
    
        IDisposable OnChange(Action<TOptions, string> listener);
      }
    }
    

    它有一个 OnChange 方法,也就是说可以监听它的变更

    public OrderService(IOptionsMonitor<OrderServiceOptions> options)
    {
        _options = options;
    
        _options.OnChange(option =>
        {
            Console.WriteLine($"配置更新了,最新的值是:{_options.CurrentValue.MaxOrderCount}");
        });
    }
    

    启动程序,修改配置,可以看到输出配置变化,也就是说可以在单例模式下监听到 Options 的变化

    通常情况下,在设计服务的时候,会在 ConfigureServices 添加配置注入、服务注入,但是当配置多起来的时候,注入代码就会非常多

    那么如何使代码结构更加良好?

    实际上可以把服务注册的代码放在静态扩展方法里,使得 ConfigureServices 更加简洁

    namespace Microsoft.Extensions.DependencyInjection
    {
        public static class OrderServiceExtensions
        {
            public static IServiceCollection AddOrderService(this IServiceCollection services,IConfiguration configuration)
            {
    
                services.Configure<OrderServiceOptions>(configuration);
                services.AddSingleton<IOrderService, OrderService>();
                return services;
            }
        }
    }
    

    这样在 Startup 的注册就变得更为简单了

    services.AddOrderService(Configuration.GetSection("OrderService"));
    

    我们在设计系统的时候会涉及大量的 service,所以我们可以把 service 的注册提炼在扩展方法里,不同的模块用不同的扩展方法隔开,使模块之间更加清晰,代码的结构也更加的清晰

    那么实际上我们在设计服务的时候,还有一些特殊的述求,比如说把配置读取出来之后,还需要在内存里面进行一些特殊的处理,我们就可以使用动态配置的方式

    动态配置的方式是在我们的 Configure 的代码之后,调用 PostConfigure 的方法,这里需要配置 OrderServiceOptions

    {
        public static class OrderServiceExtensions
        {
            public static IServiceCollection AddOrderService(this IServiceCollection services,IConfiguration configuration)
            {
    
                services.Configure<OrderServiceOptions>(configuration);
                
                services.PostConfigure<OrderServiceOptions>(options =>
                {
                    options.MaxOrderCount += 20;
                });
                
                services.AddSingleton<IOrderService, OrderService>();
                return services;
            }
        }
    }
    

    启动程序,可以看到输出动态增加了20

    知识共享许可协议

    本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。

    欢迎转载、使用、重新发布,但务必保留文章署名 郑子铭 (包含链接: http://www.cnblogs.com/MingsonZheng/ ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。

    如有任何疑问,请与我联系 (MingsonZheng@outlook.com) 。

  • 相关阅读:
    课程开始的第一次作业
    第四次寒假作业——实现五种语言的选择
    关于改良报告与学习总结(Ⅰ)
    Vue路由守卫之路由独享守卫
    Vue路由守卫之组件内路由守卫
    Vue中如何插入m3u8格式视频,3分钟学会!
    Vue中如何使用less
    第一章 初识爬虫
    【JQuery】注册中实现图片预览
    【Python】多种方式实现生成验证码
  • 原文地址:https://www.cnblogs.com/MingsonZheng/p/12405741.html
Copyright © 2020-2023  润新知