【Nacos】nacos @NacosValue 动态配置刷新 源码解析

1 原理思想

Nacos 采用的是 Pull 模式,但并不是简单的 Pull,而是一种长轮训机制,它结合 Push 和 Pull 两者的优势(nacos并没有push)。客户端采用长轮训的方式定时发起 Pull 请求,去检查服务端配置信息是否发生了变更,如果发生了变更,则客户端会根据变更的数据获得最新的配置。所谓的长轮训,是客户端发起轮训请求之后,服务端如果有配置发生变更,就直接返回。

如果客户端发起 Pull 请求后,发现服务端的配置和客户端的配置是保持一致的,那么服务端会先 “Hold” 住这个请求,也就是服务端拿到这个连接之后在指定的时间段内一直不返回结果,直到这段时间内配置发生变化,服务端会把原来 “Hold” 住的请求进行返回。Nacos 服务端收到请求之后,先检查配置是否发生了变更,如果没有,则设置一个定时任务,延期 29.5s 执行,并且把当前的客户端长轮训加入 allSubs 队列。这个时候有两种方式触发该链接结果的返回:// 后面单独看config server的源码解析

  1. 第一种是在等待 29.5s 后触发自动检查机制,这个时候不管配置有没有发生变化,都会把结果返回客户端。而 29.5s 就是这个长连接保持的时间。

  2. 第二种是在 29.5s 内任意一个时刻,通过 Nacos Dashboard 或者 API 的方式对配置进行了修改,这会触发一个事件机制,监听该事件的任务会遍历 allSubs 队列,找到发生变更的配置项对应的 ClientLongPolling 任务,将变更的数据通过该任务的连接进行返回,就完成一次 “推送” 操作。

这样既能够保证客户端实时感知配置的变化,也降低了服务端的压力。其中,这个长连接的回话超时时间默认是 30s。

2 实现:当远程文件发生变更后【 长轮询】

--->com.alibaba.nacos.client.config.impl.ClientWorker.LongPollingRunnable  实现

3 源码分析

   3.1系统启动 注册listener

    通过:初始化---->使用默认的publisher;

    springboot 是配置的天堂所以一定有个ConfigAutoConfiguration+ConfigBeanDefinitionRegistrar的组合

  • --->org.springframework.context.support.AbstractApplicationContext#invokeBeanFactoryPostProcessors // bean定义
  • --->org.springframework.context.support.PostProcessorRegistrationDelegate#invokeBeanDefinitionRegistryPostProcessors // bean定义
  • --->org.springframework.context.annotation.ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry //bean定义
  • --->org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader#loadBeanDefinitionsFromRegistrars // 启动类注解入口
  • --->com.alibaba.nacos.spring.context.annotation.config.NacosConfigBeanDefinitionRegistrar#registerBeanDefinitions
  • ----// 配置 来源com/alibaba/boot/nacos-config-spring-boot-autoconfigure/0.2.7/nacos-config-spring-boot-autoconfigure-0.2.7.jar!/META-INF/spring.factories
  • org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ com.alibaba.boot.nacos.config.autoconfigure.NacosConfigAutoConfiguration
  • [com.alibaba.boot.nacos.config.autoconfigure.NacosConfigAutoConfiguration]
  • --->import
  • [com.alibaba.nacos.spring.context.annotation.config.NacosConfigBeanDefinitionRegistrar]
  • --->com.alibaba.nacos.spring.util.NacosBeanUtils#invokeNacosPropertySourcePostProcessor
  • --->com.alibaba.nacos.spring.core.env.NacosPropertySourcePostProcessor#postProcessBeanFactory
  • --->com.alibaba.nacos.spring.core.env.NacosPropertySourcePostProcessor#processPropertySource
  • --->com.alibaba.nacos.spring.core.env.NacosPropertySourcePostProcessor#addListenerIfAutoRefreshed
  • --->com.alibaba.nacos.spring.context.event.config.EventPublishingConfigService#addListener // [DelegatingEventPublishingListener] 做监听者
  • --->com.alibaba.nacos.spring.factory.CacheableEventPublishingNacosServiceFactory // 事件发布工厂
  • --->com.alibaba.nacos.spring.context.event.config.EventPublishingConfigService // 完成监听实例化

   3.2 Bean 配置属性注册到Map>

  • -->org.springframework.context.support.AbstractApplicationContext#registerBeanPostProcessors
  • -->org.springframework.context.support.PostProcessorRegistrationDelegate#registerBeanPostProcessors
  • -->org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#initializeBean
  • -->org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsBeforeInitialization
  • -->org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsBeforeInitialization
  • -->org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsBeforeInitialization
  • -->com.alibaba.nacos.spring.context.annotation.config.NacosValueAnnotationBeanPostProcessor#postProcessBeforeInitialization
  • -->com.alibaba.nacos.spring.context.annotation.config.NacosValueAnnotationBeanPostProcessor#doWithFields
  • -->com.alibaba.nacos.spring.context.annotation.config.NacosValueAnnotationBeanPostProcessor#doWithAnnotation
  • [com.alibaba.nacos.spring.context.annotation.config.NacosValueAnnotationBeanPostProcessor.NacosValueTarget]
  • // 完成-->com.alibaba.nacos.spring.context.annotation.config.NacosValueAnnotationBeanPostProcessor#doWithFields 初始化到改MAP中

   3.3 长轮询监听到变更

     立即刷新CacheData,调用listener [DelegatingEventPublishingListener]监听者发送context事件

     // 当收到推送事件之后---->包装容器上下文事件----->主动更新MAP对应的bean实例属性

  • --->com.alibaba.nacos.spring.context.event.config.DelegatingEventPublishingListener#receiveConfigInfo
  • --->com.alibaba.nacos.spring.context.event.config.DelegatingEventPublishingListener#publishEvent
  • --->com.alibaba.nacos.spring.context.event.DeferredApplicationEventPublisher // 使用默认的publisher
  • --->com.alibaba.nacos.spring.context.event.DeferredApplicationEventPublisher#publishEvent // 触发容器事件
  • --->com.alibaba.nacos.spring.context.annotation.config.NacosValueAnnotationBeanPostProcessor#onApplicationEvent

因为有着Map记录了,占位符和所属实例的关系,所以依靠反射轻松改变了bean的配置值

0

  • --->com.alibaba.nacos.spring.context.annotation.config.NacosValueAnnotationBeanPostProcessor#setField
  • --->ReflectionUtils.makeAccessible(field);
  • field.set(bean, convertIfNecessary(field, propertyValue));

 

4 完成配置动态刷新

     依靠反射轻松改变了bean的配置值

5 小结:

  1.   注意LOGGER 依赖关系,nacos输出日志
  2.   springboot 引入starter常用套路
已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页