Soul网关源码阅读(四)—— sofa插件详解

Soul网关源码阅读(四)—— sofa插件详解

概述

经过divide插件和dubbo插件篇的讲解,soul网关的核心概念和大体运行机制已经熟悉的差不多了。我们知道了,更换插件对于soul网关来说无非不就是更换soul网关到后端服务的通信协议,剩下的逻辑都是共同的。

因此这篇文章在介绍sofa插件使用方式的同时,我们还会接着上一篇dubbo篇,续集往下深入,梳理一下soul-admin与soul-bootstrap服务进行数据同步的具体细节。

实践操作

  1. 启动admin服务。

  2. 在bootstrap服务pom.xml中添加对sofa插件的依赖,并启动bootstrap服务。

    <dependency>
               <groupId>com.alipay.sofa</groupId>
               <artifactId>sofa-rpc-all</artifactId>
               <version>5.7.6</version>
           </dependency>
           <dependency>
               <groupId>org.apache.curator</groupId>
               <artifactId>curator-client</artifactId>
               <version>4.0.1</version>
           </dependency>
           <dependency>
               <groupId>org.apache.curator</groupId>
               <artifactId>curator-framework</artifactId>
               <version>4.0.1</version>
           </dependency>
           <dependency>
               <groupId>org.apache.curator</groupId>
               <artifactId>curator-recipes</artifactId>
               <version>4.0.1</version>
           </dependency>
           <dependency>
               <groupId>org.dromara</groupId>
               <artifactId>soul-spring-boot-starter-plugin-sofa</artifactId>
               <version>${last.version}</version>
    </dependency>
    
  3. 打开admin服务对sofa插件的支持开关。
    在这里插入图片描述

  4. 启动soul-examples/soul-examples-sofa服务。

  5. 观测添加@SoulSofaClient注解的api是否在admin注册成功
    在这里插入图片描述

  6. 使用postman请求网关进行sofa的转发测试。
    在这里插入图片描述

源码阅读

今天阅读源码的思路,从上一篇Soul网关源码学习(三)——Dubbo插件详解 接着往下分析。

上一篇分析了如果soul网关使用websocket与admin进行通信,admin服务中WebsocketCollector类的send方法负责将数据发送给soul网关。那么网关服务是如何接收admin传过来的数据并且如何使用的呢?

查看项目结构可以发现,有一个子模块soul-sync-data-center,可以判断这个模块负责与admin的数据同步。该模块下面有几个子模块对应不同协议的数据同步方式,正好与DataSyncConfiguration类中配置的一致,这里我们着重分析soul-sync-data-websocket模块。

先查看一下目录结构:
在这里插入图片描述
先分析WebsocketSyncDataService类,该类的两个成员变量,clients和executor。

  • executor是一个定时任务类型的线程执行器,每30秒检测soul与admin的websocket连接是否正常,如果断掉则重连。

    executor.scheduleAtFixedRate(() -> {
          
          
                        try {
          
          
                            if (client.isClosed()) {
          
          
                                boolean reconnectSuccess = client.reconnectBlocking();
                                if (reconnectSuccess) {
          
          
                                    log.info("websocket reconnect is successful.....");
                                } else {
          
          
                                    log.error("websocket reconnection is error.....");
                                }
                            }
                        } catch (InterruptedException e) {
          
          
                            log.error("websocket connect is error :{}", e.getMessage());
                        }
                    }, 10, 30, TimeUnit.SECONDS);
    
  • clients用来持有与admin的连接,client的实现类是SoulWebsocketClient,它扩展了WebSocketClient。

    public final class SoulWebsocketClient extends WebSocketClient {
          
              
    		//...
        public SoulWebsocketClient(final URI serverUri, final PluginDataSubscriber pluginDataSubscriber,
                                   final List<MetaDataSubscriber> metaDataSubscribers, final List<AuthDataSubscriber> authDataSubscribers) {
          
          
            super(serverUri);
            this.websocketDataHandler = new WebsocketDataHandler(pluginDataSubscriber, metaDataSubscribers, authDataSubscribers);
        }
    		//...监听到消息执行逻辑。
       @Override
        public void onMessage(final String result) {
          
          
            handleResult(result);
        }
    		//执行具体的handler
        @SuppressWarnings("ALL")
        private void handleResult(final String result) {
          
          
            WebsocketData websocketData = GsonUtils.getInstance().fromJson(result, WebsocketData.class);
            ConfigGroupEnum groupEnum = ConfigGroupEnum.acquireByName(websocketData.getGroupType());
            String eventType = websocketData.getEventType();
            String json = GsonUtils.getInstance().toJson(websocketData.getData());
            websocketDataHandler.executor(groupEnum, json, eventType);
        }
    }
    

    该类的主要任务是,通过构造参数将不同类型的业务处理handler通过构造函数封装到websocketDataHandler中,然后onMessage方法接收admin的消息,并执行对应的handle方法,我们可以看到之前handle目录下的handler就是来负责处理具体逻辑的。

    我们选择PluginDataHandler来分析一下:
    在这里插入图片描述
    可以看到真正执行处理的PluginDataSubscriber,它是插件进行与admin同步数据的接口,可以看到其定义了很多数据交互的方法。PluginDataSubscriber的具体实现类是CommonPluginDataSubscriber。

    CommonPluginDataSubscriber维护了一个key为插件名称,value 为handler的Map集合。

        public CommonPluginDataSubscriber(final List<PluginDataHandler> pluginDataHandlerList) {
          
          
            this.handlerMap = pluginDataHandlerList.stream().collect(Collectors.toConcurrentMap(PluginDataHandler::pluginNamed, e -> e));
        }
    

    其核心方法是subscribeDataHandler:
    在这里插入图片描述

    这里不同的事件类型调用相应的处理器去做数据处理,真正存储admin同步来的数据的类是BaseDataCache。

    打开BaseDataCache类:
    在这里插入图片描述
    好了,终于找到真正缓存数据的地方了,可以看到分别这里使用了一个ConcurrentMap用来缓存admin同步来的数据。

思考总结

今天简单的学习了sofa插件的使用,另一方面接着上一篇继续分析了数据同步的源码,了解到了如何使用一个hashmap来做数据同步,了解了如何维持一个connection连接(定时任务检测重连,类似心跳检测)。

猜你喜欢

转载自blog.csdn.net/u010084384/article/details/112795031