当前位置: 首页 > article >正文

【深入理解SpringCloud微服务】深入理解nacos配置中心(三)——服务端启动与获取配置源码分析

【深入理解SpringCloud微服务】深入理解nacos配置中心(三)——服务端启动与获取配置源码分析

  • 原理回顾
    • 服务端启动
    • 获取配置
  • 源码分析
    • 服务端启动
      • ExternalDumpService#init()
      • ConfigCacheService#dump()
    • 获取配置

原理回顾

服务端启动

我们在《宏观理解nacos配置中心原理》的文章说到了,服务端启动的原理。

在这里插入图片描述

会调用DumpService查询MySQL,然后把查询到的配置信息dump到磁盘成为一个个的配置文件,每个DataId对应一个配置文件。

获取配置

然后服务端接收到获取配置文件的请求时,从磁盘中查询对应文件返回,而不是去查询数据库。

在这里插入图片描述

源码分析

服务端启动

ExternalDumpService#init()

我们以nacos配置的数据库是MySQL的情况为例子,DumpService的实现类就是ExternalDumpService。

nacos配置中心其实就是一个SpringBoot应用,它的启动就是SpringBoot启动。然后由于ExternalDumpService的init()方法被@PostConstruct注解修饰,因此在初始化ExternalDumpService时init()方法会被调用。

    @PostConstruct
    @Override
    protected void init() throws Throwable {
        dumpOperate(processor, dumpAllProcessor, dumpAllBetaProcessor, dumpAllTagProcessor);
    }

在这里插入图片描述

    protected void dumpOperate(DumpProcessor processor, DumpAllProcessor dumpAllProcessor,
            DumpAllBetaProcessor dumpAllBetaProcessor, DumpAllTagProcessor dumpAllTagProcessor) throws NacosException {
        ...
                dumpConfigInfo(dumpAllProcessor);
       ...
    }
   private void dumpConfigInfo(DumpAllProcessor dumpAllProcessor) throws IOException {
        ...
                dumpAllProcessor.process(new DumpAllTask());
            ...
    }

在这里插入图片描述

经过一轮调用,进入到DumpAllProcessor#process方法。

    @Override
    public boolean process(NacosTask task) {
    	// 查询最大的id值
        long currentMaxId = persistService.findConfigMaxId();
        long lastMaxId = 0;
        while (lastMaxId < currentMaxId) {
        	// 分页查询MySQL
            Page<ConfigInfoWrapper> page = persistService.findAllConfigInfoFragment(lastMaxId, PAGE_SIZE);
            if (page != null && page.getPageItems() != null && !page.getPageItems().isEmpty()) {
                for (ConfigInfoWrapper cf : page.getPageItems()) {
                	long id = cf.getId();
                    lastMaxId = Math.max(id, lastMaxId);
                    ...
                    // 调用ConfigCacheService把查询到的每一条记录dump到磁盘成一个配置文件
                    ConfigCacheService.dump(cf.getDataId(), cf.getGroup(), cf.getTenant(), cf.getContent(),
                            cf.getLastModified(), cf.getType(), cf.getEncryptedDataKey());
                    
                    ...
                }
                ...
            }
            ...
        }
        return true;
    }

在这里插入图片描述

ConfigCacheService#dump()

    public static boolean dump(String dataId, String group, String tenant, String content, long lastModifiedTs,
            String type, String encryptedDataKey) {
        // 根据dataId, group, tenant三元组算出一个groupKey(其实就是拼接)
        String groupKey = GroupKey2.getKey(dataId, group, tenant);
        ...
        try {
        	// 根据配置文件内容算出一个md5值
            final String md5 = MD5Utils.md5Hex(content, Constants.ENCODE);
        	...
        		// 把配置文件内容dump到磁盘成为一个配置文件
                DiskUtil.saveToDisk(dataId, group, tenant, content);
            }
            // 更新缓存中的md5值
            updateMd5(groupKey, md5, lastModifiedTs, encryptedDataKey);
            return true;
        } ...
    }

ConfigCacheService的dump方法首先根据配置文件内容算出一个md5值,然后把配置文件内容dump到磁盘成为一个配置文件,最后更新缓存中的md5值。

在这里插入图片描述

    public static void updateMd5(String groupKey, String md5, long lastModifiedTs, String encryptedDataKey) {
    	// 从一个ConcurrentHashMap<String, CacheItem>中根据groupKey获取CacheItem
        CacheItem cache = makeSure(groupKey, encryptedDataKey, false);
        // 如果CacheItem等于空,或者CacheItem中的md5值与刚算出的md5值不匹配,则进入分支
        if (cache.md5 == null || !cache.md5.equals(md5)) {
        	// 更新CacheItem的md5值
            cache.md5 = md5;
            cache.lastModifiedTs = lastModifiedTs;
            // 发布一个LocalDataChangeEvent事件,异步通知客户端
            NotifyCenter.publishEvent(new LocalDataChangeEvent(groupKey));
        }
    }

ConfigCacheService的updateMd5方法首先从从一个ConcurrentHashMap<String, CacheItem>中根据groupKey获取CacheItem,然后判断如果CacheItem等于空或者CacheItem中的md5值与刚算出的md5值不匹配则进入分支,由于是刚启动,因此CacheItem肯定等于空,所以会进入if分支。然后if分支中更新CacheItem的md5值,并发布一个发布一个LocalDataChangeEvent事件异步通知客户端。

在这里插入图片描述

这里NotifyCenter.publishEvent(new LocalDataChangeEvent(groupKey))发布的事件不是Spring的事件监听机制,而是nacos自己封装的事件监听机制。

获取配置

由于已经查询MySQL然后dump到磁盘成配置文件了,因此当接收到获取配置的RPC请求时,就不需要再去查询MySQL,而是读取磁盘的配置文件即可。

我们可以根据客户端发送GRPC远程调用时创建的request对象的类型,找到服务端处理该请求的Handler。我们在上一篇文章《客户端启动源码分析》中说到request请求对象的类型是ConfigQueryRequest。

通过ConfigQueryRequest,就可以找到处理获取配置请求的方法在ConfigQueryRequestHandler的handle方法。

    public ConfigQueryResponse handle(ConfigQueryRequest request, RequestMeta meta) throws NacosException {
        
        try {
            return getContext(request, meta, request.isNotify());
        } catch (...) {...}
        
    }

ConfigQueryRequestHandler的handle方法调用getContext方法。

在这里插入图片描述

    private ConfigQueryResponse getContext(ConfigQueryRequest configQueryRequest, RequestMeta meta, boolean notify)
            throws UnsupportedEncodingException {
        ...
        						// 从磁盘根据dataId, group, tenant三元组读取配置文件
                                file = DiskUtil.targetFile(dataId, group, tenant);
                            ...
                        // 读取配置文件中的内容,设置到response对象中
                        content = readFileContent(file);
                        response.setContent(content);
                        ...
        return response;
    }

在这里插入图片描述


http://www.kler.cn/a/293778.html

相关文章:

  • 文件夹被占用了无法删除怎么办?强制粉碎文件夹你可以这样操作
  • idea 解决缓存损坏问题
  • 2019年下半年试题二:论软件系统架构评估及其应用
  • Java 网络编程(一)—— UDP数据报套接字编程
  • AI 扩展开发者思维方式:以 SQL 查询优化为例
  • Linux设置socks代理
  • UNI-APP 溢出隐藏显示省略号
  • Hive SQL 分组与连接操作详解
  • html css网页制作成品
  • java计算机毕设课设—企业员工信息管理系统(附源码、文章、相关截图、部署视频)
  • 【STM32开发】GPIO最全解析及应用实例
  • Linux磁盘管理(精要)
  • 【数据结构-二维前缀和】力扣1277. 统计全为 1 的正方形子矩阵
  • SQL的高级查询练习知识点(day24)
  • centos8stream 修改为阿里云yum源
  • SQL进阶技巧:如何取时间序列最新完成状态的前一个状态并将完成状态的过程进行合并?
  • DataX用hdfsreader导入或导出hive数据
  • EmguCV学习笔记 C# 第10章 人脸识别
  • BMP280气压传感器详解(STM32)
  • Github优秀开源项目推荐
  • react antd table expandable defaultExpandAllRows 不生效问题
  • 知识付费最新版知识付费做的最好的平台,网创资源知识付费 知识付费网站搭建,搭建知识付费APP平台教学:在线教育系统源码。
  • NGINX 中配置负载均衡器
  • Dance with compiler - EP1
  • 单调栈的实现
  • libvncclient编写多线程qt的VNC客户端