前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【想进大厂还不会阅读源码】ShenYu源码-重构同步数据服务

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

原创
作者头像
思考的陈
修改2024-03-08 20:48:58
560
修改2024-03-08 20:48:58

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

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

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

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

一、前瞻

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

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

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

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

二、探索

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

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

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

代码语言:java
复制
public class NacosSyncDataService extends AbstractNodeDataSyncService implements SyncDataService {
}

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

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

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

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

代码语言:java
复制
    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就是留给各个子类来实现的功能,不同的配置中心,不同获取配置的方法。

代码语言:java
复制
protected abstract String getServiceConfig(String key, Consumer<String> updateHandler, Consumer<String> deleteHandler);

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

代码语言:java
复制
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实现的功能。

代码语言:java
复制
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这种方式来阅读源码的乐趣呢!不仅获得了知识,还获得了一次开源贡献,何乐而不为呢

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

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、前瞻
  • 二、探索
  • 三、拓展
相关产品与服务
微服务引擎 TSE
微服务引擎(Tencent Cloud Service Engine)提供开箱即用的云上全场景微服务解决方案。支持开源增强的云原生注册配置中心(Zookeeper、Nacos 和 Apollo),北极星网格(腾讯自研并开源的 PolarisMesh)、云原生 API 网关(Kong)以及微服务应用托管的弹性微服务平台。微服务引擎完全兼容开源版本的使用方式,在功能、可用性和可运维性等多个方面进行增强。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档