本以为这是个简单的问题,后来细看,这个问题不是抽完半包烟估计是看不出来的!源码调试环境和之前的有些不同,客户端实现配置中心需要添加额外依赖!如下!
这个是获取配置详情的!这个是监听配置变化的,注意这里使用的是长轮询,并不是长链接,这里我发现阿里的中间件比较喜欢使用长轮询的方式,看过RocketMQ的朋友应该也知道RocketMQ使用的也是长轮询的机制获取消息的!由于Nacos-客户端配置中心比较复制,而且有多个监听,这里就不以之前分析服务注册和心跳机制那样一条线写下来了,而是分为多条线来写,这里多条线有些事并行,但是也是有启动顺序的,这让文章也稍微好写一点!主线程初始化简单介绍 这个线程只要就两个功能,第一个是开启一个10毫秒的定时任务,第二个就是将Nacos中对应的配置拉到本地目录,稍微简单点,不像其他监听线程,乱的一逼!启动入口这个是SpringCloudContext牵引加载的进入locate方法第一块代码进入后流程如下!加载Nacos配置中心进入NacosConfigServiceNacosConfigService构造方法的代码如下:初始化一个HttpAgent,这里有调用装饰器模式,实际工作的类是ServerHttpAgent,MetricsHttpAgent内部也调用了ServerHttpAgent的方法,增加了监控统计信息ClientWorker是一个客户端的一个工作类,agent作为参数传入ClientWorker,可以基本猜测到里面会用到agent做一些远程调用相关的事情!这里ClientWorker创建是一个比较核心的方法!切入ClientWorker这里有三块比较重要的代码块,我们逐个分析!第一块是创建一个线程池,executor这个线程池是用来检查配置的第二块也是创建了一个线程池,但是目前并没有直接使用到,executorService这个线程主要是用于实现客户端定时长轮询的,也就是长轮询监听Nacos服务端配置变化的!第三块就是使用executor线程池开启一个定时任务,每隔10毫秒,执行checkConfigInfo();方法,检查一次配置信息这里checkConfigInfo();方法比较有意思,也比较恶心!我们切入checkConfigInfo();方法!深入checkConfigInfo();方法cacheMao:用来存储监听变更的缓存集合,key是根据dataId/group/tenant(租户)拼接的值,value是对应存储在Nacos服务器上的配置文件内容长轮询任务拆分:默认情况下,每个长轮询LongPollingRunnable任务处理3000个监听配置集,如果超过3000个,则需要启动多个LongPollingRunnable去执行不幸的是这里服务刚开始启动,走到这里并不会进入这个if判断,也就是下面这部分代码根本不会执行for (int i = (int) currentLongingTaskCount; i < longingTaskCount; i++) { // 要判断任务是否在执行 这块需要好好想想。 任务列表现在是无序的。变化过程可能有问题 executorService.execute(new LongPollingRunnable(i)); } currentLongingTaskCount = longingTaskCount;原因是currentLongingTaskCount的初始值是0,cacheMap的size也是0,所以这里的if进入逻辑不会执行,这里也就是每隔10毫秒执行到if后从新在执行,一致等待if判断条件准入!第一块代码就分析到这里,我们回到下面这个地方,开始分析第二块逻辑进入loadApplicationConfiguration方法loadApplicationConfiguration这个方法中调用了loadNacosDataIfPresent,然后又循环调用loadNacosDataIfPresent,这里第一次调用dataId为server-consumer.yaml,第二次则是加了激活环境的,也就是server-consumer-dev.yaml注意这里如果Nacos服务端没有添加对应配置文件,那么下面执行远程http请求Nacos服务的时候会404直接切入loadNacosDataIfPresent方法深入build方法调用loadNacosData方法直接进入getConfigInner方法这个方法其实逻辑比较简单,就是从本地配置,本地配置不是客户端程序内存 等下进去各位就知道了,从本地配置中获取配置内容,如果不为空,那么第二块逻辑直接返回,如果为空那么交给第三块逻辑发起远程请求从Nacos服务端获取对应配置worker.getServerConfig(dataId, group, tenant, timeoutMs);深入LocalConfigInfoProcessor.getFailover(agent.getName(), dataId, group, tenant);方法这个LocalConfigInfoProcessor类建议先大致过一遍,就知道我刚才为什么标注红色的字体说不是客户端程序内存,而是本地配置文件!这里操作的就是本地配置文件!文件位于下面这个目录!注意,客户端程序刚启动的时候是没有这个数据文件的!那么按照代码逻辑,这里会向Nacos服务端发起http请求获取对应配置!那么我们进入getServerConfig方法深入getServerConfig方法注意这里请求Nacos服务返回的结果是受dataId,group影响的,如果Nacos配置中心中不存在对应的配置,那么返回的状态码就不同!那么这里也就有了switch分支判断!如果对应查询配置不存在,那么就会返回状态码为404content = worker.getServerConfig(dataId, group, tenant, timeoutMs);这里请求的接口和文章刚开始列出的Nacos文档中的API对上了!然后根据http相应信息switch中更具http状态码判断分支逻辑这里都调用了LocalConfigInfoProcessor.saveSnapshot方法,无非就是最后有个config参数不同,这个参数也就是远程调用Nacos服务返回的配置信息了!切入saveSnapshot方法这里有个分支,会根据config是否为null,如果不为空,那么写入本地配置文件,如果为空的话,那么剔除掉文件!那么到这里主线程逻辑就分析完了,至此,Nacos服务中的配置已经写到本地目录,然后客户端开启了一个10毫秒的线程检查cacheMap的size变化!触发监听简单介绍监听ApplicationReadyEvent事件当主线任务执行好了后,会发布一个ApplicationReadyEvent事件,那么NacosContextRefresher中就监听了这个事件,那么就会进入NacosContextRefresher的onApplicationEvent方法进入registerNacosListenersForApplications方法进入registerNacosListener方法这里就是构造了Listener,和添加了Listener,进入addListener方法!调用addTenantListeners方法调用方法addCacheDataIfAbsent这个方法有点巧妙!CacheData cache = getCache(dataId, group, tenant);getCache其实就是获取cacheMap中的数据,但是这里刚开始是没有值的,因为值还没加载到cacheMap中,还在本地配置文件中cache = new CacheData(configFilterChainManager, agent.getName(), dataId, group, tenant);这行代码创建CacheData对象就是读取本地配置文件,这个构造方法如下loadCacheContentFromDiskLocal方法就是去取本地配置的!最后回到最后那步代码cacheMap.set(copy);这行代码可谓是画龙点睛之作,这里往cacheMap中set了值,也就是说改变了cacheMap的size,那么主线程中开启的那个10毫秒的定时任务就会感知到!那么这部分逻辑就结束了开启监听触发监听部分也就是改变了cacheMap的大小,然后导致主线程中的定时任务感知到,那么我们把视角切回到主线程中的定时任务!回看checkConfigInfo方法这里使用executorService线程次开启了LongPollingRunnable线程任务!进入LongPollingRunnable线程任务对象这块代码有点长,挺简单的,我们分块来看遍历cacheMap检查本地配置!ListchangedGroupKeys = checkUpdateDataIds(cacheDatas, inInitializingCacheList);通过长轮询请求Nacos服务器,检查服务端对应的配置是否发生变更,进入checkUpdateDataIds方法调用checkUpdateConfigStr方法和文章开头部分监听API对上了这是30秒的长轮询,如果30秒Nacos服务端查询的配置没有变动,那么返回空,如果30之内任意时间有变动立马返回,如果返回有变化,那么就会得到要获取的配置,通过String content = getServerConfig(dataId, group, tenant, 3000L);getServerConfig和主线程部分的是同一个,逻辑也是一样,获取Nacos配置,然后写入到本地这一块又是重复执行当前任务!那么基本上到这里真个Nacos客户端获取配置源码就分析完了!