【想进大厂还不会阅读源码】ShenYu源码-重构同步数据服务

简介: ShenYu源码阅读📚。我们看下PR的标题和Concersation的头一句,大概意思就是重构注册中心数据同步到ShenYu网关的方式。大家看看重构了有没好处呢?不仅获得了知识,还获得了一次开源贡献,何乐而不为呢

相信大家碰到源码时经常无从下手🙃,不知道从哪开始阅读,面对大量代码晕头转向,索性就读不下去了,又浪费了一次提升自己的机会😭。


我认为有一种方法,可以解决大家的困扰!那就是通过阅读某一次开源的【PR】、【ISSUE】,从这个入口出发去阅读源码!!


至此,我们发现自己开始从大量堆砌的源码中脱离开来😀。豁然开朗,柳暗花明又一村。

ShenYu是一个异步的,高性能的,跨语言的,响应式的 API 网关。有关ShenYu的介绍可以戳这

一、前瞻

好了,今天我们来看看本次的PR提交

在这里插入图片描述

我们看下PR的标题和Concersation的头一句,大概意思就是重构注册中心数据同步到ShenYu网关的方式

阅读源码前,我们先思考我们本次要阅读的线索:

  1. 贡献者是怎么重构的
  2. 重构了相对于原先旧方式有什么好处

二、探索

本次PR代码量还是很巨大了,从PR提交可以看到一共有82次提交!!!不要怕,我们先整体浏览下整个提交,在高的维度去看贡献者具体做了什么动作。

在这里插入图片描述
总的来说可以分为两部分,重构提供同步数据的客户端、重构使用同步数据的Admin调用端(准确来说是监听端,下文都书写为调用端更容易理解)。

我们先看看Nacos的重构步骤,其他注册中心重构逻辑大致也是一致的。

public class NacosSyncDataService extends AbstractNodeDataSyncService implements SyncDataService {
   
}

Nacos同步数据的NacosSyncDataService继承了AbstractNodeDataSyncService,我们应该重点阅读父类约定的规则和提供的实现。

在这里插入图片描述

上图可以看到有两个抽象类AbstractNodeDataSyncService、AbstractPathDataSyncService,NodeData、PataData顾名思义前者是处理Nacos这类节点类型的注册中心,后者就是处理ZooKeeper这类的路径节点注册中心。

大家思考下,本次PR提交一直提到同步数据,那究竟靠什么来同步数据?其实Nacos有配置中心的功能,同步数据也就是同步Nacos配置中心的数据,方便ShenYu修改数据就立刻生效而不用重启

可以看到AbstractNodeDataSyncServicestartWatch方法,各个watch方法来监听配置中心的数据。

    protected void startWatch() {
   
        try {
   
            final List<String> pluginNames = getConfigListOnWatch(changeData.getPluginDataId() + DefaultNodeConstants.POINT_LIST, updateData -> {
   
                List<String> changedPluginNames = GsonUtils.getInstance().fromList(updateData, String.class);
                watcherPlugin(changedPluginNames);
            });

            watcherPlugin(pluginNames);

            watchCommonList(changeData.getAuthDataId() + DefaultNodeConstants.JOIN_POINT, this::cacheAuthData, this::unCacheAuthData);

            watchCommonList(changeData.getMetaDataId() + DefaultNodeConstants.JOIN_POINT, this::cacheMetaData, this::unCacheMetaData);

        } catch (Exception e) {
   
            throw new ShenyuException(e);
        }
    }

其中getServiceConfig就是留给各个子类来实现的功能,不同的配置中心,不同获取配置的方法。

protected abstract String getServiceConfig(String key, Consumer<String> updateHandler, Consumer<String> deleteHandler);

我们来看看获取Nacos配置的子类NacosSyncDataService是怎么获取的。

public class NacosSyncDataService extends AbstractNodeDataSyncService implements SyncDataService {
   

    private final ConfigService configService;

    @Override
    protected String getServiceConfig(final String key, final Consumer<String> updateHandler, final Consumer<String> deleteHandler) {
   
        try {
   
            if (watchCache.containsKey(key)) {
   
                return null;
            }
            final Listener listener = new Listener() {
   
                @Override
                public Executor getExecutor() {
   
                    return null;
                }

                @Override
                public void receiveConfigInfo(final String configInfo) {
   
                    try {
   
                        if (StringUtils.isBlank(configInfo) && deleteHandler != null) {
   
                            deleteHandler.accept(key);
                        } else {
   
                            updateHandler.accept(configInfo);
                        }
                    } catch (Exception e) {
   
                        LOG.error("nacos sync listener receiveConfigInfo error", e);
                    }
                }
            };
            final String serviceConfig = configService.getConfigAndSignListener(key, NacosPathConstants.GROUP, 3000, listener);
            watchCache.put(key, listener);
            return serviceConfig;
        } catch (Exception e) {
   
            throw new ShenyuException(e);
        }
    }
}

可以看到该类通过调用Nacos提供的ConfigService服务来进行获取配置,同时Listener就是监听器的作用。

大致看完了客户端的重构,我们来看看ShenYu Admin调用端的重构。既然客户端是同步配置中心的数据,那调用端也就是起到创建、更新、删除配置的作用

在这里插入图片描述

回顾下上文提到的AbstractNodeDataSyncService和AbstractPathDataSyncService,上图的AbstractNodeDataChangeListener和AbstractPathDataChangeListener同样是实现某些具体的功能,需要子类实现的延迟到子类实现。

我们看下子类NacosDataChangedListener实现的功能。

public class NacosDataChangedListener extends AbstractNodeDataChangedListener {
   

    private static final Logger LOG = LoggerFactory.getLogger(NacosDataChangedListener.class);

    private final ConfigService configService;

    public NacosDataChangedListener(final ConfigService configService) {
   
        super(new ChangeData(NacosPathConstants.PLUGIN_DATA_ID, NacosPathConstants.SELECTOR_DATA_ID,
                NacosPathConstants.RULE_DATA_ID, NacosPathConstants.AUTH_DATA_ID, NacosPathConstants.META_DATA_ID,
                NacosPathConstants.PROXY_SELECTOR_DATA_ID, NacosPathConstants.DISCOVERY_DATA_ID));
        this.configService = configService;
    }

    @Override
    public void doPublishConfig(final String dataId, final Object data) {
   
        try {
   
            configService.publishConfig(
                    dataId, 
                    NacosPathConstants.GROUP, 
                    GsonUtils.getInstance().toJson(data),
                    ConfigType.JSON.getType());
        } catch (NacosException e) {
   
            LOG.error("Publish data to nacos error.", e);
            throw new ShenyuException(e.getMessage());
        }
    }

    @Override
    public void doDelConfig(final String dataId) {
   
        try {
   
            configService.removeConfig(
                    dataId,
                    NacosPathConstants.GROUP);
        } catch (NacosException e) {
   
            LOG.error("Publish data to nacos error.", e);
            throw new ShenyuException(e.getMessage());
        }
    }

    @Override
    public String getConfig(final String dataId) {
   
        try {
   
            return configService.getConfig(dataId, NacosPathConstants.GROUP, NacosPathConstants.DEFAULT_TIME_OUT);
        } catch (NacosException e) {
   
            LOG.error("Get data from nacos error.", e);
            throw new ShenyuException(e.getMessage());
        }
    }

}

正如上文我们所说的:

既然客户端是同步配置中心的数据,那调用端也就是起到创建、更新、删除配置的作用

三、拓展

不会吧,大家还记得我们的阅读线索2吗,重构了相对于原先旧方式有什么好处?

在这里插入图片描述

我们仔细看下上文提到的AbstractNodeDataSyncService和AbstractPathDataSyncService等这几个抽象类就知道了,抽象父类把重复的功能实现,而获取配置这种各个配置中心有不同的获取方式,就留给了各个配置中心的子类实现

而原先的旧代码,每个不同的配置中心都要实现一套重复的方法代码,代码耦合且不易扩展。大家看看重构了有没好处呢。

咦?仔细看了下,贡献者的类注释写错了啊。

在这里插入图片描述

开心又获得了一次开源贡献!想看下开源PR戳这

在这里插入图片描述

好了,今天的分享就到这了。大家能否感受到通过PR这种方式来阅读源码的乐趣呢!不仅获得了知识,还获得了一次开源贡献,何乐而不为呢

创作不易,不妨点赞、收藏、关注支持一下,各位的支持就是我创作的最大动力❤️

相关文章
|
5月前
|
设计模式 前端开发 Java
KnowStreaming系列教程第二篇——项目整体架构分析
KnowStreaming系列教程第二篇——项目整体架构分析
45 0
|
7月前
|
存储 前端开发 JavaScript
潮玩宇宙大逃杀无聊猿卷轴模式系统开发详细规则丨步骤需求丨方案项目丨技术架构丨源码功能
确定游戏类型和规则:明确无聊猿卷轴模式游戏类型和游戏规则,包括敌人类型、地图设计、任务类型、战斗机制等。
|
3月前
|
Dubbo 中间件 应用服务中间件
【想进大厂还不会阅读源码】ShenYu源码-支持motan协议
ShenYu源码阅读📚。原来的插件只支持 motan2 协议,并且是硬编码的,本次修改使MotanRpcExt 得到增强。我们可以通过以上的线索来思考我们本次的阅读线索,贡献者是做了什么实现了增强motan插件、这个motan的插件的功能是什么。
35 2
|
3月前
|
API Nacos
【想进大厂还不会阅读源码】ShenYu源码-接入注册中心发现服务
ShenYu源码阅读。相信大家碰到源码时经常无从下手🙃,不知道从哪开始阅读😭。我们先思考下我们的阅读线索,贡献者是怎么添加发现服务的。这些发现服务是怎么和项目集成的,让ShenYu网关能从注册中心获取节点信息?
47 1
【想进大厂还不会阅读源码】ShenYu源码-接入注册中心发现服务
|
8月前
|
消息中间件 SQL 关系型数据库
「要点解析」分布式高级商城业务:分布式事务,满足你的好奇心
数据库事务的几个特性:原子性(Atomicity)、一致性(Consistency)、隔离性或者独立性(Lsolation)和持久性(Durabilily),简称就是ACID原子性:一系列的操作整体不可拆分,要么同时成功,要么同时失败一致性:数据在事务的前后,业务整体一致转账:A:1000;B:1000;转 200;事务成功:A:800;B:1200隔离性:事务之间互相隔离持久性:一旦事务成功,数据一定会落盘在数据库
90 0
|
9月前
|
SQL 缓存 负载均衡
项目高并发问题解决方案合集
这道题是比较典型的题吧,也是我第一个公司入职的时候,面试官问我的,当时我回答只能说是星星之火,还不能燎原那种,差点被面试官给浇灭。
74 0
|
10月前
|
设计模式 安全 Java
基于设计模式改造短信网关服务实战篇(设计思想、方案呈现、源码)
基于设计模式改造短信网关服务实战篇(设计思想、方案呈现、源码)
214 0
|
11月前
|
缓存 JSON 前端开发
腾讯开源的 hel 提供了加载远程模块的能力,谈谈它的实现原理
腾讯开源的 hel 提供了加载远程模块的能力,谈谈它的实现原理
152 0
|
测试技术 Python
【第五篇-完结篇】XiaoZaiMultiAutoAiDevices之改造扩展
在前面系列文章中有讲到,使用configparser,ini格式的文件作为配置文件,在新增或者删除其中的值时,会丢失所有注释,所以在框架源码注释中我有写到,如果对这方面比较介意或者是有需求的话,可以进行更改配置文件。
106 0