• Nacos是怎样实现配置动态更新的?如何动态更新bean?


    一.前言.

       Nocos( Dynamic Naming and Configuration Service)是阿里开源的,集配置中心和注册中心为一体的微服务框架.
    此篇主要说明Nacos在作为配置中心时是怎样做到动态更新配置的.

    二.实现方式猜想

    其实要实现动态配置更新,目前主要有两种方式:

    1. 客户端每隔一段时间进行定时加载配置,这种很容易实现,但是性能不高,并且在一定时间范围内无法做到及时更新.
    2. 服务端在发生配置变更的时候向客户端发起一个通知,客户端收到通知后,去加载变更的配置.这种比较高效.

    三.Nocas具体实现

    nacos是第二种思想.

    SDK(也就是客户端) 通过 GRPC(一个开源RPC框架,用于服务调用) 长连接监听配置变更,Server 端对比 Client 端配置的 MD5 和本地 MD5是否相等,不相等推送配置变更.
    在这里插入图片描述

    四.如何动态更新bean的呢?

    在服务端发送通知,客户端拿到最新的配置后,通常需要动态更新一些bean,那是怎么做的呢?

    1. 首先标识需要动态更新的bean对象.
      使用SpringCloud中的@RefreshScope注解,这个注解主要有两个作用.
           (1) @Scope(“refresh”):将其作用域标识为特殊的refresh
           (2) ScopedProxyMode.TARGET_CLASS :当ScopedProxyMode 为TARGET_CLASS 的时候会给当前创建的bean 生成一个代理对象,会通过代理对象来访问(这个后面会重点说明)
    2. 客户端拿到最新的配置后,将配置更新到Spring容器中的Environment对象中.
    3. 清除bean缓存,这里的缓存和通常说的三级缓存有点不一样,是BeanLifecycleWrapperCache,缓存了所有@RefreshScope 标注的对象.
    4. 对所有需要动态更新的bean重新执行实例化,初始化的过程,执行完毕重新放到缓存中.

    补充知识:
           在IOC容器里面,有一个map类型的scopes的缓存,他会根据scope名称不同,分为restart、request、session、refresh、application(至于为啥没有单例和多例,因为单例的缓存已经单独放在SingletonObjects缓存里面了,多例就更不用说,压根就不需要缓存)。

    在这里插入图片描述

    五.原理细节理解

    问题1:
          当某个对象加了@RefreshCode注解,一旦该对象的某个值要更新,那么所有依赖到该对象的对象也需要更新,那是怎么做的呢?难道全部都从新实例化初始化吗?要是这样的话就有些不合理了.

    答案:
          其实Spring这里设计的还是很巧妙的.
          正常来讲,Spring管理的所有对象的属性注入在项目一启动就已经确定了,那在启动后如果想更新某个对象值,不仅要更新本对象,还要更新所有依赖到该对象的对象.
          那为了简化操作,Spring在依赖对象和属性之间加了一层代理,就是前面提到的ScopedProxyMode.TARGET_CLASS.当有对象标识为这个的时候,那么所有用到该对象的地方拿到的其实都是一个代理.

    举例:
    定义一个测试类:TestController.加了@RefreshScope注解,也就标识了ScopedProxyMode.TARGET_CLASS.
    在这里插入图片描述
    当TestController被其他类作为属性注入时,就会注入一个代理类.
    在这里插入图片描述
    当使用代理类去执行我们自己的方法的时候,会进入代理方法中,在代理方法中会去获取真正的对象.
    在这里插入图片描述
          在此方法getTarget()中,会根据不同情况判断是新增还是从缓存中获取对象.
    假如是单例模式:会直接从一级缓存(SingletonObjects)中获取
    假如是多例:直接重新走实例化初始化的过程
    假如是其他:比如说是refresh,会从对应的缓存(BeanLifecycleWrapperCache)中获取.如下图.
    在这里插入图片描述
          那么当testController动态更新后,BeanLifecycleWrapperCache缓存中会对该对象进行更新,此时依赖到该对象的对象也能够获取到最新的对象,做到动态更新bean及其关联方.

          这也是为什么如果某个对象加了refreshScope注解,那么该对象放到singletonObjects缓存中的就是一个代理对象,真正的对象在Scope.refresh.BeanLifecycleWrapperCache中.

    问题2:
    使用@RefreshScope的对象是单例的还是多例的?

    答案:
          可能是单例的,也可能是多例的.这取决于该对象有没有被动态更新过,如果更新过,那么其他bean获取到的该对象也就变了.否则,一直是同一个对象.

    ======================================================================================================
    如果你需要阅读专业书籍来提升自己,可以关注博主的公众号,回复 图书即可获得几百本程序员必读书籍.

    包含以下所有分类中的各种经典书籍.
    在这里插入图片描述
    006QslZHly8h66jmes3esj30go0gowg9.jpg

    今天的分享就到这里了,有问题可以在评论区留言,均会及时回复呀.
    我是bling,未来不会太差,只要我们不要太懒就行, 咱们下期见.
    在这里插入图片描述

  • 相关阅读:
    C语言:计算阶乘与计算从1加到100的代码对比:都要用到3个变量,不同之处在于表达式
    chatgpt论文润色 & 降重
    17、JAVA入门——多态、抽象方法和抽象类
    谷粒学苑 Vue +NUXT +SpringCloud 部署到服务器
    Remote & Local File Inclusion (RFI/LFI)-文件包含漏洞
    c# ValueTuple
    JavaScript 的常量和变量
    C++挑选书籍
    asp.net乡村旅游管理系统VS开发sqlserver数据库web结构c#编程Microsoft Visual Studio
    IPIDEA的使用方式
  • 原文地址:https://blog.csdn.net/wangliangluang/article/details/127040023