Soul网关源码阅读(九)—— 数据同步之WebSocket

Soul网关源码阅读(九)—— 数据同步之WebSocket

概要

之前我们简单介绍了soul网关是通过admin进行数据同步的,这一篇我们来消息介绍一下soul网关使用websocket来进行数据同步的关机设计和详细流程。

流程图

在这里插入图片描述

详细解析

1. WebsocketSyncDataConfiguration

首先知道网关与admin之间需要同步的数据类型有哪些:

  • 插件Plugin
  • 元数据MetaData
  • 认证数据AuthData

我们那需要为每一种数据类型编写不同的业务逻辑:

  • PluginDataSubcriber
  • MetaDataSubcriber
  • AuthDataSubscriber

这里我们Websocket下对应实现类分别是:

  • CommonPluginDataSubscriber
  • MetaDataAllSubscriber
  • SignAuthDataSubscriber

WebsocketSyncDataConfiguration配置类,组合了以上对象,并且初始化了WebsocketSyncDataService对象。WebsocketSyncDataService对象是用来进行数据同步的类型,它组合了一个WebSocketClient用来与admin服务进行socket通信。

2. WebsocketSyncDataService

WebsocketSyncDataService在初始化的时候,会出发WebSocketClient初始化并且通过websocket连接到admin,连接到配置的端口:ws://localhost:9095/websocket

Admin服务WebSocketCollectoronMessage方法会触发soul的请求:

    @OnMessage
    public void onMessage(final String message, final Session session) {
    
    
        if (message.equals(DataEventTypeEnum.MYSELF.name())) {
    
    
            try {
    
    
                ThreadLocalUtil.put(SESSION_KEY, session);
                SpringBeanUtils.getInstance().getBean(SyncDataService.class).syncAll(DataEventTypeEnum.MYSELF);
            } finally {
    
    
                ThreadLocalUtil.clear();
            }
        }
    }

Admin中通过SyncDataServiceImpl来syncAll方法来进行所有数据类型的同步,由于是soul刚启动,所以需要同步全量数据,这里通过去数据库获取数据发送事件的方式,将不同ConfigGroupEnum类型发送给不同的监听器进行处理。

    @Override
    public boolean syncAll(final DataEventTypeEnum type) {
    
    
        appAuthService.syncData();
        List<PluginData> pluginDataList = pluginService.listAll();
        eventPublisher.publishEvent(new DataChangedEvent(ConfigGroupEnum.PLUGIN, type, pluginDataList));
        List<SelectorData> selectorDataList = selectorService.listAll();
        eventPublisher.publishEvent(new DataChangedEvent(ConfigGroupEnum.SELECTOR, type, selectorDataList));
        List<RuleData> ruleDataList = ruleService.listAll();
        eventPublisher.publishEvent(new DataChangedEvent(ConfigGroupEnum.RULE, type, ruleDataList));
        metaDataService.syncData();
        return true;
    }

这里分别进行了auth、plugin、selector、rule、metadata数据的事件发送。

4. DataChangedEventDispatcher

发送的事件被DataChangedEventDispatcher监听器接收,它会根据不同的DataChangedEvent事件的ConfigGroupEnum类型,将事件委托给不同的listener进行处理。

这listener的实现类有四种,他们配置在DataSyncConfiguration,通过配置文件决定加载与否,如下所示,

在这里插入图片描述

这里我们由于只配置了WebSocketDataChangedListener,所有只会委托给WebSocketDataChangedListener的方法,进行执行:

5. WebsocketDataChangedListener

这里WebsocketDataChangedListener会将从数据库加载的信息发送给Soul

   public void onPluginChanged(final List<PluginData> pluginDataList, final DataEventTypeEnum eventType) {
    
    
        WebsocketData<PluginData> websocketData =
                new WebsocketData<>(ConfigGroupEnum.PLUGIN.name(), eventType.name(), pluginDataList);
        WebsocketCollector.send(GsonUtils.getInstance().toJson(websocketData), eventType);
    }

6. SoulWebsocketClient

Soul网关SoulWebsocketClient接收到admin推送过来的数据,出发onMessage方法执行:

    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);
    }

并使用之前在装配进来的websocketDataHandler进行处理,具体处理逻辑handler为PluginDataHandler,并根据具体的事件类型做处理,这里将调用doRefresh方法:

 @Override
    public void handle(final String json, final String eventType) {
    
    
        List<T> dataList = convert(json);
        if (CollectionUtils.isNotEmpty(dataList)) {
    
    
            DataEventTypeEnum eventTypeEnum = DataEventTypeEnum.acquireByName(eventType);
            switch (eventTypeEnum) {
    
    
                case REFRESH:
                case MYSELF:
                    doRefresh(dataList);
                    break;
                case UPDATE:
                case CREATE:
                    doUpdate(dataList);
                    break;
                case DELETE:
                    doDelete(dataList);
                    break;
                default:
                    break;
            }
        }
    }
  @Override
    protected void doRefresh(final List<PluginData> dataList) {
    
    
        pluginDataSubscriber.refreshPluginDataSelf(dataList);
        dataList.forEach(pluginDataSubscriber::onSubscribe);
    }

doRefresh方法的逻辑很简单:

  • 删除就缓存
  • 添加新缓存
    @Override
    public void onSubscribe(final PluginData pluginData) {
    
    
        subscribeDataHandler(pluginData, DataEventTypeEnum.UPDATE);
    }

数据同步逻辑结束。

总结语

这篇我们分析了使用WebSocket进行数据同步的详细逻辑,并且分析soul启动时是如何加载plugin数据的,其他的数据类型的流程是一毛一样的,只不过换成不同的handler进行处理即可。

这里由于Soul启动时有一个初始化的操作,所以通过主动请求出发了数据同步操作。之后如果admin数据同步逻辑,也会通过事件的方式触发到DataChangedEventDispatcher监听器,将对应的数据更新发送给soul,如此就完成了admin与soul之间的数据同步。

猜你喜欢

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