![](http://imgq8.q578.com/ef/1110/2837fa2886070163.jpg)
ClientWorker 的构造函数里会去创建两个线程池,executor 会每隔 10ms 进行一次配置变更的检查,executorService 主要是用来处理长轮询请求的。
![](http://imgq8.q578.com/ef/1110/94736a9c55a6acd5.jpg)
checkConfigInfo 方法中会创建一个长轮询任务丢到 executorService 线程池中去处理。
![](http://imgq8.q578.com/ef/1110/50a1b1b7804f4058.jpg)
LongPollingRunnable 的 run 方法代码有点多,主要流程如下:
获取上个章节中说到的缓存 cacheMap,然后遍历,判断如果该配置使用的是本地缓存模式,则调用 checkListenerMd5 去检查读到的本地缓存文件中内容的 Md5 跟上次更新的 Md5 是不是一样,不一样则调用 safeNotifyListener 去通知监听器处理,并且更新 listenerWrap 中的 content、Md5
![](http://imgq8.q578.com/ef/1110/4a2c392fe262bc4f.jpg)
checkUpdateDataIds 该方法中,会将所有的 dataId 按定义格式拼接出一个字符串,构造一个长轮询请求,发给服务端,Long-Pulling-Timeout 超时时间默认 30s,如果服务端没有配置变更,则会保持该请求直到超时,有配置变更则直接返回有变更的 dataId 列表。
![](http://imgq8.q578.com/ef/1110/d1134475b54a2b75.jpg)
拿到第二步有变更的 dataId 后会调用 getServerConfig 获取最新的配置内容,然后遍历调用 checkListenerMd5 去检查最新拉取的配置内容的 Md5 跟上次更新的 Md5 是不是一样,不一样则调用 safeNotifyListener 去通知监听器处理,并且更新 listenerWrap 中的 content、Md5
![](http://imgq8.q578.com/ef/1110/f3fc28d1bd073f5e.jpg)
checkListenerMd5 方法如下,主要就是判断两个 md5 是不是相同,不同则调用 safeNotifyListener 处理。
![](http://imgq8.q578.com/ef/1110/48ffc678e0d5d77f.jpg)
safeNotifyListener 方法主要就是调用监听器的 receiveConfigInfo 方法,然后更新监听器包装器中的 lastContent、lastCallMd5 字段。
![](http://imgq8.q578.com/ef/1110/5360f7f94b0a3d9e.jpg)
监听器要执行的方法我们上面也已经讲过了,这边再贴下截图,主要就是发布 RefreshEvent 事件。
![](http://imgq8.q578.com/ef/1110/4601fc9a798cedb1.jpg)
至此,Nacos 的处理流程已经结束了,RefreshEvent 事件主要由 SpringCloud 相关类来处理。
RefreshEvent 事件处理
RefreshEvent 事件会由 RefreshEventListener 来处理,该 listener 含有一个 ContextRefresher 的对象。
![](http://imgq8.q578.com/ef/1110/88d5299810f40cf0.jpg)
如下图所示,refreshEnvironment 会去刷新 Spring 环境变量,实际上是交给 updateEnvironment 方法去做的刷新,具体刷新思想就是重新创建一个 Spring 容器,然后将这个新容器中的环境信息设置到原有的 Spring 环境中。拿到所有变化的配置项后,发布一个环境变化的 EnvironmentChangeEvent 事件。
![](http://imgq8.q578.com/ef/1110/fce14896acd30863.jpg)
![](http://imgq8.q578.com/ef/1110/9025e81fbc2f9eba.jpg)
ConfigurationPropertiesRebinder 会监听 EnvironmentChangeEvent 事件,监听到事件后会对所有的标注有 ConfigurationProperties 注解的配置类进行销毁后重新初始化的操作,完之后我们的配置类中的属性就是最新的了。
![](http://imgq8.q578.com/ef/1110/1cf3646e9740cf3f.jpg)
![](http://imgq8.q578.com/ef/1110/45f8ef3340af941c.jpg)
这里我们说到了会对标有 ConfigurationProperties 注解的配置类进行 rebind,那对于普通组件类里标有 @Value 注解的属性要怎么生效呢?这个其实需要配合 @RefreshScope 注解来生效的。
我们继续回到上述的 refresh() 方法,接着会有一步 refreshAll 的操作,会调用父类的 destroy 方法。
![](http://imgq8.q578.com/ef/1110/f7a431a046f4c464.jpg)
![](http://imgq8.q578.com/ef/1110/0f9c5b12860c07e6.jpg)