【想进大厂还不会阅读源码】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这种方式来阅读源码的乐趣呢!不仅获得了知识,还获得了一次开源贡献,何乐而不为呢

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

相关文章
|
2月前
|
设计模式 前端开发 Java
KnowStreaming系列教程第二篇——项目整体架构分析
KnowStreaming系列教程第二篇——项目整体架构分析
60 0
|
2月前
|
资源调度 监控 前端开发
第七章(原理篇) 微前端技术之依赖管理与版本控制
第七章(原理篇) 微前端技术之依赖管理与版本控制
|
2月前
|
消息中间件 存储 负载均衡
精华推荐 | 【深入浅出 RocketMQ原理及实战】「底层源码挖掘系列」透彻剖析贯穿RocketMQ的消费者端的运行核心的流程(上篇)
精华推荐 | 【深入浅出 RocketMQ原理及实战】「底层源码挖掘系列」透彻剖析贯穿RocketMQ的消费者端的运行核心的流程(上篇)
37 1
|
2月前
|
API Nacos
【想进大厂还不会阅读源码】ShenYu源码-接入注册中心发现服务
ShenYu源码阅读。相信大家碰到源码时经常无从下手🙃,不知道从哪开始阅读😭。我们先思考下我们的阅读线索,贡献者是怎么添加发现服务的。这些发现服务是怎么和项目集成的,让ShenYu网关能从注册中心获取节点信息?
【想进大厂还不会阅读源码】ShenYu源码-接入注册中心发现服务
|
2月前
|
Dubbo 中间件 应用服务中间件
【想进大厂还不会阅读源码】ShenYu源码-支持motan协议
ShenYu源码阅读📚。原来的插件只支持 motan2 协议,并且是硬编码的,本次修改使MotanRpcExt 得到增强。我们可以通过以上的线索来思考我们本次的阅读线索,贡献者是做了什么实现了增强motan插件、这个motan的插件的功能是什么。
|
11月前
|
SQL 缓存 负载均衡
项目高并发问题解决方案合集
这道题是比较典型的题吧,也是我第一个公司入职的时候,面试官问我的,当时我回答只能说是星星之火,还不能燎原那种,差点被面试官给浇灭。
86 0
|
11月前
|
前端开发
前端学习笔记202305学习笔记第二十三天-重构和代码迁移1
前端学习笔记202305学习笔记第二十三天-重构和代码迁移1
36 0
|
Kubernetes Cloud Native Dubbo
Higress 开源后,我们整理了开发者最关心的 15 个问题
云原生网关 Higress 开源后,引起了开发者们的热烈讨论,我们整理了大家在 GitHub、钉群、微信群讨论的问题,并将回答汇总如下,方便各位更准确的读懂 Higress,也非常欢迎您和我们一起共建、定义 Higress。
305 3
Higress 开源后,我们整理了开发者最关心的 15 个问题
|
Java 程序员 Maven