soul网关系列(七):soul-admin与网关数据同步之websocket方式

这一篇主要介绍soul-admin的配置/注册数据如何通过websocket同步到soul-bootstrap

一、概述

在这里插入图片描述

  • websocket和zookeeper同步方式,提供增量更新的方式,生产实践中也基本是这两种方式
  • http长连接和nacos的同步方式,都是提供全量更新的方式,效率上存在一定的影响。

按上一篇的数据流分析,soul-admin会将配置信息同步至soul getway,如图所示,这一篇主要是讲解websocket同步方式。

二、相关配置说明

websocket的数据同步方式也是soul网关默认的同步方式,相应的配置有如下

  • soul-admin application-local配置文件
    在这里插入图片描述
  • soul-admin/bootstrap pom.xml中引入依赖
<dependency>
    <groupId>org.springframework.boot</groupId>
	  <artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
  • soul-bootstrap的配置文件application-local.yml中配置soul-admin的ws地址
    在这里插入图片描述
    注意路径中的websocket这个可以理解为ws的topic,与之对应的是soul-admin中的
    在这里插入图片描述

三、soul-admin源码解析

在这里插入图片描述
昨天客户端注册至soul-admin之后,在入库之后调用了publishEvent()方法,以这个为数据传输起点分析
在这里插入图片描述
其中publishEvent已经是Spring框架中ApplicationEventPublisher的方法了,搜一下

  • ApplicationEventPublisher

notify all matching listeners registered with this application of an application event.Events may be framework events
(such as ContextRefreshedEvent) or application-specific events.
通知所有注册至这个应用的监听者,通知事件可能为框架事件或者是特定应用程序的事件。

与之对应的类为ApplicationListener,肯定有一个地方实现了这个接口

  • ApplicationListener

ApplicationListener接口是由 Spring 提供的事件订阅者必须实现的接口,我们一般把该 Service 关心的事件类型作为泛型传入。处理事件,通过 event.getSource() 即可拿到事件的具体内容

publish和listener中间这里传递的是DataChangedEvent,查看DataChangedEvent的调用者猜测为DataChangedEventDispatcher,这个也的确实现了ApplicationListener接口
在这里插入图片描述
DataChangedEventDispatcher负责两件事情

  1. 得到所有实现了DataChangedListener的监听器
  2. 循环监听器们,进行相应的方法调用(这里可以优化,因为会存在多个同步方式)
@Component
public class DataChangedEventDispatcher implements ApplicationListener<DataChangedEvent>, InitializingBean {

    private ApplicationContext applicationContext;

    private List<DataChangedListener> listeners;

    public DataChangedEventDispatcher(final ApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
    }
	// 循环监听器们,进行相应的方法调用(这里可以优化,因为会存在多个同步方式)
    @Override
    @SuppressWarnings("unchecked")
    public void onApplicationEvent(final DataChangedEvent event) {
        for (DataChangedListener listener : listeners) {
            switch (event.getGroupKey()) {
                case APP_AUTH:
                    listener.onAppAuthChanged((List<AppAuthData>) event.getSource(), event.getEventType());
                    break;
                case PLUGIN:
                    listener.onPluginChanged((List<PluginData>) event.getSource(), event.getEventType());
                    break;
                case RULE:
                    listener.onRuleChanged((List<RuleData>) event.getSource(), event.getEventType());
                    break;
                case SELECTOR:
                    listener.onSelectorChanged((List<SelectorData>) event.getSource(), event.getEventType());
                    break;
                case META_DATA:
                    listener.onMetaDataChanged((List<MetaData>) event.getSource(), event.getEventType());
                    break;
                default:
                    throw new IllegalStateException("Unexpected value: " + event.getGroupKey());
            }
        }
    }
    //得到所有实现了DataChangedListener的监听器
    @Override
    public void afterPropertiesSet() {
        Collection<DataChangedListener> listenerBeans = applicationContext.getBeansOfType(DataChangedListener.class).values();
        this.listeners = Collections.unmodifiableList(new ArrayList<>(listenerBeans));
    }

}

那所有的DataChangeListener是怎么注入的呢,搜索DataChangeListener的所有实现方法
在这里插入图片描述
发现这里是根据配置文件里的配置项实现的自动注入bean,因为我们在yml配置中开启了soul.sync.websocket.enabled,所以监听器可以初始化,而后DataChangedEventDispatcher根据listener触发相应的更新操作。

public class WebsocketDataChangedListener implements DataChangedListener {

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

    @Override
    public void onSelectorChanged(final List<SelectorData> selectorDataList, final DataEventTypeEnum eventType) {
        WebsocketData<SelectorData> websocketData =
                new WebsocketData<>(ConfigGroupEnum.SELECTOR.name(), eventType.name(), selectorDataList);
        WebsocketCollector.send(GsonUtils.getInstance().toJson(websocketData), eventType);
    }

    @Override
    public void onRuleChanged(final List<RuleData> ruleDataList, final DataEventTypeEnum eventType) {
        WebsocketData<RuleData> configData =
                new WebsocketData<>(ConfigGroupEnum.RULE.name(), eventType.name(), ruleDataList);
        WebsocketCollector.send(GsonUtils.getInstance().toJson(configData), eventType);
    }

    @Override
    public void onAppAuthChanged(final List<AppAuthData> appAuthDataList, final DataEventTypeEnum eventType) {
        WebsocketData<AppAuthData> configData =
                new WebsocketData<>(ConfigGroupEnum.APP_AUTH.name(), eventType.name(), appAuthDataList);
        WebsocketCollector.send(GsonUtils.getInstance().toJson(configData), eventType);
    }

    @Override
    public void onMetaDataChanged(final List<MetaData> metaDataList, final DataEventTypeEnum eventType) {
        WebsocketData<MetaData> configData =
                new WebsocketData<>(ConfigGroupEnum.META_DATA.name(), eventType.name(), metaDataList);
        WebsocketCollector.send(GsonUtils.getInstance().toJson(configData), eventType);
    }

}

至此soul-admin的ws流程完毕
在这里插入图片描述

四、soul-bootstrap处理流程

找到依赖包里的soul-sync-data-websocket
找到WebSocketClient的具体实现,看具体的处理过程,debug一下。
在这里插入图片描述
一步步走下去
在这里插入图片描述
后面就是具体的更新缓存的逻辑了,这一块设计层层进行,后面单独一篇讲。

五、参考链接

Soul网关(六)---- Websocket 同步数据

已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: 1024 设计师:白松林 返回首页