SpringCloudAlibaba 微服务组件 Nacos 之配置中心源码深度解析( 三 )


配置热更新上面章节我们讲了服务启动的时候从远程 Nacos 服务端拉到配置,以及服务启动后对需要支持热更新的配置都注册了一个监听器,这个章节我们来说下配置变动后具体是怎么处理的 。
回到上述说过的 NacosPropertySourceLocator 的 locate 方法看看,该方法首先会获取一个 ConfigService 。

SpringCloudAlibaba 微服务组件 Nacos 之配置中心源码深度解析

文章插图
NacosConfigManager 中会进行一个 ConfigService 单例对象的创建,创建流程最终会委托给 ConfigFactory,使用反射方式创建一个 NacosConfigService 的实例对象,NacosConfigService 是一个很核心的类,配置的获取,监听器的注册都需要经此 。
SpringCloudAlibaba 微服务组件 Nacos 之配置中心源码深度解析

文章插图
我们看下 NacosConfigService 的构造函数,会去创建一个 ClientWorker 类的对象,这个类是实现配置热更新的核心类 。
SpringCloudAlibaba 微服务组件 Nacos 之配置中心源码深度解析

文章插图
ClientWorker 的构造函数里会去创建两个线程池,executor 会每隔 10ms 进行一次配置变更的检查,executorService 主要是用来处理长轮询请求的 。
SpringCloudAlibaba 微服务组件 Nacos 之配置中心源码深度解析

文章插图
checkConfigInfo 方法中会创建一个长轮询任务丢到 executorService 线程池中去处理 。
SpringCloudAlibaba 微服务组件 Nacos 之配置中心源码深度解析

文章插图
LongPollingRunnable 的 run 方法代码有点多,主要流程如下:
  1. 获取上个章节中说到的缓存 cacheMap,然后遍历,判断如果该配置使用的是本地缓存模式,则调用 checkListenerMd5 去检查读到的本地缓存文件中内容的 Md5 跟上次更新的 Md5 是不是一样,不一样则调用 safeNotifyListener 去通知监听器处理,并且更新 listenerWrap 中的 content、Md5

SpringCloudAlibaba 微服务组件 Nacos 之配置中心源码深度解析

文章插图
  1. checkUpdateDataIds 该方法中,会将所有的 dataId 按定义格式拼接出一个字符串,构造一个长轮询请求,发给服务端,Long-Pulling-Timeout 超时时间默认 30s,如果服务端没有配置变更,则会保持该请求直到超时,有配置变更则直接返回有变更的 dataId 列表 。

SpringCloudAlibaba 微服务组件 Nacos 之配置中心源码深度解析

文章插图
  1. 拿到第二步有变更的 dataId 后会调用 getServerConfig 获取最新的配置内容,然后遍历调用 checkListenerMd5 去检查最新拉取的配置内容的 Md5 跟上次更新的 Md5 是不是一样,不一样则调用 safeNotifyListener 去通知监听器处理,并且更新 listenerWrap 中的 content、Md5

SpringCloudAlibaba 微服务组件 Nacos 之配置中心源码深度解析

文章插图
checkListenerMd5 方法如下,主要就是判断两个 md5 是不是相同,不同则调用 safeNotifyListener 处理 。
SpringCloudAlibaba 微服务组件 Nacos 之配置中心源码深度解析

文章插图
safeNotifyListener 方法主要就是调用监听器的 receiveConfigInfo 方法,然后更新监听器包装器中的 lastContent、lastCallMd5 字段 。
SpringCloudAlibaba 微服务组件 Nacos 之配置中心源码深度解析

文章插图
监听器要执行的方法我们上面也已经讲过了,这边再贴下截图,主要就是发布 RefreshEvent 事件 。
SpringCloudAlibaba 微服务组件 Nacos 之配置中心源码深度解析

文章插图
至此,Nacos 的处理流程已经结束了,RefreshEvent 事件主要由 SpringCloud 相关类来处理 。
RefreshEvent 事件处理RefreshEvent 事件会由 RefreshEventListener 来处理,该 listener 含有一个 ContextRefresher 的对象 。

经验总结扩展阅读