目录
配置中心是SpringCloud系统中常见的一种技术方案,配置中心区别于传统的各个系统当中分散的配置方式,它对系统中的配置文件进行集中式、统一管理。
使用配置中心好处有:
①、通过配置中心,可以使得配置标准化、格式统一化。
②、当配置信息发生变动时,修改实时生效,无需要重新重启服务器,可以实时去调整相关对应的业务。
最近在做技术调研形成落地方案的时候,突然想到了nacos的动态配置刷新,于是想去看下nacos动态配置到底怎么实现的,今天抽出点时间看了下nacos配置中心源码实现。
所以,本篇文章就介绍nacos是怎么扩展spring实现自己的配置数据动态加载的。
首先第一点需要知道的是nacos动态配置从nacos角度来看核心是通过长轮询(LongPolling)来实现的,我们不妨先从nacos角度来看其长轮询实现方式,然后再看和spring的整合。
所谓长轮询,就是服务器接收到请求后,hold连接一段时间暂时不返回消息,直到进行相关处理完毕后才返回响应信息并关闭连接,客户端接收到响应信息后,进行相关处理,处理完毕后再向服务器发送新的请求。
所以在一次nacos客户端连接服务端当中,服务端断开连接也就有了两种情况:
①、服务端数据发生了变化,需要推送到客户端,向客户端推送数据,断开连接。
②、在一段时间内没有数据发生改变,超时断开连接。
下面我们来看nacos是怎么实现LongPolling的。
nacos长轮询逻辑是在类ClientWorker当中。
这里我们先从类ClientWorker的构造方法看起,因为下面讲的和spring集成部分都是在类ClientWorker的构造方法的上层部分,等说到和spring继承的时候我们再衔接到类ClientWorker的构造方法这个地方。
其实就是拿到项目中配置的nacos服务端地址拼接上uri后直接和nacos服务端进行通信,获取已经发生改变的key。
然后下面整个一个for循环就是对changedGroupKeys进行遍历,从遍历出来的每一项groupKey解析出来dataId、group、tenant,然后通过这三个参数执行getServerConfig()方法获取到真正改变的内容,更新到本地缓存cacheMap中的CacheData。
然后接下来的for循环核心执行的就是通知监听器刷新nacos数据。
我们直接看cacheData.checkListenerMd5()方法的执行逻辑。
遍历所有的监听器,最终执行safeNotifyListener()这个方法很显然这个方法中创建了一个Runnable任务,最终通过监听器Listener里面的线程池或者直接执行这个Runnable任务。
所以,我们接下来重点看Runnable任务执行的逻辑。
这个Runnable任务里面核心逻辑是这行代码。
表示接收到动态修改的内容。
所以我们直接看这行代码的逻辑。
要看这行代码的逻辑,首先需要搞懂这个listener是哪个实现类,在这里先告诉大家,这个实现类是在NacosContextRefresher里面注册nacos监听器的时候创建的内部类,如果自己debug一下也能找到。
NacosContextRefresher这个类其实已经是和spring整合的桥梁了,接下来我们直接看NacosContextRefresher里面注册nacos监听器的时候创建的内部类,我们先看是怎么实现动态刷新数据的,等会再看和spring整合。
这个内部类innerReceive()方法正是实现了AbstractSharedListener这个抽象类,而AbstractSharedListener这个抽象类的顶层接口就是Listener,我们看这个内部类中的核心逻辑有两处:
①、nacosRefreshHistory通过链表的方式记录nacos数据变更历史
②、通过ApplicationContext.publishEvent()方法刷新容器
很显然,我们想看的逻辑正是刷新容器这行代码。
ApplicationContext.publishEvent()方法刷新容器的这行代码我跟着源码跟踪的很深、很久,但是我陷入了疑惑,随着我不断的跟踪spring的源码,发现这行代码的底层是spring的时间发布机制在不重启spring容器的前提下,动态的刷新容器,但是好像和nacos动态刷新加载最新的刚才传过来的数据String configInfo没有关系,也就是说,我想着从nacos服务端拿过来的数据并没有加载到spring中啊。
在这里疑惑了很久,因为跟踪源码并没有发现数据并没有加载到spring中,只是看到了在不重启spring容器的前提下,动态的刷新spring容器,所以这个时候我就猜想,动态的刷新spring容器怎么才能拿到nacos最新的数据呢,突然一个灵感,spring容器重启的时候不就是会初始化第一次从nacos拿最新的数据嘛,后续才通过nacos长轮询获取数据。
然后我在NacosConfigManager这个类的构造方法打了个debug断点,因为这个类就是spring容器启动的时候第一次初始化创建nacos需要的一些组件、开启定时任务等核心逻辑。
果然,是进到了这个debug,也就印证了我的猜想。
上面我们主要是从nacos长轮询LongPolling的核心逻辑倒推监听器怎么执行最后到和spring整合的地方,这里我们详细看下和spring整合的部分。
和spring整合首先看类NacosConfigAutoConfiguration、NacosConfigBootstrapConfiguration这两个配置类,这两个配置类主要创建了nacos的一些核心组件。
重点看类NacosConfigManager和NacosContextRefresher。
NacosConfigManager是创建nacos长轮询的定时任务,定时执行长轮询的定时任务,是nacos配置更新的启动点。
NacosContextRefresher是和spring整合的桥梁,实现了ApplicationContextAware用来获取ApplicationContext,实现了ApplicationListener用来通知spring发布时间通知。
在发布事件通知的逻辑中就注册了nacos的监听器。
nacos注册的监听器的这个内部类正是我们刚才看的动态刷新数据通知spring发布事件通知的那个内部类。
通过这两个类就实现了spring容器启动的时候启动nacos长轮询监听服务端数据变更和监听到数据变更后动态获取最新的nacos配置数据。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/bian-cheng-ri-ji/51744.html