Soul源码阅读02-websocket同步数据原理讲解 第一章

·  阅读 285

Soul网关-websocket同步数据原理讲解 第一章

在上一章中已经看到,针对于接口注册的网关的流程,大体的通用逻辑都是先进行业务逻辑的判断(是否重复、是否符合),在判断完后进行了一系列的修改数据库表的操作,最后通过Spring的事件发布机制,发布了一个类型为DataChangedEvent的事件。

为什么要发布事件呢?在soul的官方文档已经很明确的说明了,网关要做到高性能,要尽快的进行规定路径的寻址,如果每次都从库里取注册的地址,毫无疑问会增加网络IO的消耗,所以在soul设计的时候将所有网关请求转发所需要的东西,全部都加载到了JVM的内存中,而为了避免对地址的一些修改、删除、新增等操作,soul目前采用了websocket、zookeeper(3.0版本)、http长轮询、nacos(3.0版本)等解决方案,来实现了一个近实时的操作。

  • 这个 DataChangedEvent的事件中到底包含了哪些东西呢?
    
    // 事件的操作类型
    private DataEventTypeEnum eventType;
    // 配置组(我更习惯理解为各个模块)
    private ConfigGroupEnum groupKey;
    
    //还有一个 List<?> source 属性 这个属性 继承于ApplicationEvent
复制代码
  • DataEventTypeEnum中定义了DELETE、CREATE、UPDATE、REFRESH、MYSELF五种操作类型,按照字面意思除了最后一个MYSELF有些歧义外,其他都好理解(MYSELF暂时先放过,后期在找)。
  • ConfigGroupEnum中定义了APP_AUTH、PLUGIN、RULE、SELECTOR、META_DATA五种类型,而在我们的基于SpringMvc的接口注册中,最后只发布了RULE和SELECTOR的事件,从这里也能大体看出soul把用户的权限、插件的使用、接口规则·、选择器、元数据都放到了内存中(暂时大部分都不知道干啥用的)。

接下来进入正题让我们来看一下针对于websocket,soul是如何实现近实时更新的。

  • 找到订阅事件的地址,最后找到了DataChangedEventDispatcher(可以全局搜索implements ApplicationListener<DataChangedEvent找到对应的类),
@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接口的所有实现全部加载到list中
    @Override
    public void afterPropertiesSet() {
        Collection<DataChangedListener> listenerBeans = applicationContext.getBeansOfType(DataChangedListener.class).values();
        this.listeners = Collections.unmodifiableList(new ArrayList<>(listenerBeans));
    }

}
复制代码
  • 在上面的代码中我们可以看到DataChangedEventDispatcher类在初始化的时候实现了InitializingBean通过Spring的上下文获取到了属于DataChangedListener这个类型的所有对象并且加载到了当前类的list中,在接收到事件后又通过模块类型选择执行不同listener的方法。那DataChangedListener对象又是干什么的呢?
public interface DataChangedListener {
    //收到AppAuth时调用此方法。
    default void onAppAuthChanged(List<AppAuthData> changed, DataEventTypeEnum eventType) {}
    //收到插件时调用此方法。
    default void onPluginChanged(List<PluginData> changed, DataEventTypeEnum eventType) {}
    //收到选择器时调用此方法。
    default void onSelectorChanged(List<SelectorData> changed, DataEventTypeEnum eventType) {}
    //收到元数据时调用此方法。
    default void onMetaDataChanged(List<MetaData> changed, DataEventTypeEnum eventType) {}
    //收到Rule时调用此方法。
    default void onRuleChanged(List<RuleData> changed, DataEventTypeEnum eventType) {}
}
复制代码
  • 通过上述的接口方法,大概能明确DataChangedListener接口提供了ConfigGroupEnum下类型的数据处理,而它有哪些实现类呢?

  • 可以看到一共提供了5种实现,大概扫了一下结构,其实实际只有4种,http长轮询、nacos、zookeeper、websocket,而多余的那个抽象实现其实是和http长轮询联用的,暂时忽略,后期测试http长轮询的同步再逐步跟进。

  • 由于本篇文章 主要针对于websocket同步数据,所以主要看对应的websocket实现类的逻辑,大体如下

public class WebsocketDataChangedListener implements DataChangedListener {
    
    
    //省略其余实现 其余实现的代码逻辑 与这个一致
   
    @Override
    public void onSelectorChanged(final List<SelectorData> selectorDataList, final DataEventTypeEnum eventType) {
        System.out.println("进入 websocket selector chanage");
        WebsocketData<SelectorData> websocketData =
                new WebsocketData<>(ConfigGroupEnum.SELECTOR.name(), eventType.name(), selectorDataList);
        WebsocketCollector.send(GsonUtils.getInstance().toJson(websocketData), eventType);
    }
}
复制代码
  • 可以看到 在websocket的监听实现类里,在接收到传递的数据后,又进行封装了一次自己对应的DTO,然后发送给了对应的websocket

本篇文章大概先到期为止,后续的流程大概跟了一下,有些许的长,下篇文章接着讲

分类:
后端
标签: