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,未来不会太差,只要我们不要太懒就行, 咱们下期见.
在这里插入图片描述

  • 9
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 7
    评论
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员bling

义父,感谢支持

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值