Soul网关源码分析-10期(周总结)


后台与网关数据同步 (Websocket篇)



后台如何建立Websocket?


DataSyncConfiguration
WebsocketListener
WebsocketCollector

DataSyncConfiguration: 作为 Spring Bean 的配置工厂, 可以根据配置信息, 构建各类监听器, 包括 HTTP 长轮询方式、Zookeeper 方式、Nacos 方式、Websocket 方法.

@Configuration
public class DataSyncConfiguration {
  
  // soul-admin 项目的配置信息中, 使用 soul.sync.websocket.enabled 开启或关闭 websocket
  @Configuration
  @ConditionalOnProperty(name = "soul.sync.websocket.enabled", havingValue = "true", matchIfMissing = true)
  @EnableConfigurationProperties(WebsocketSyncProperties.class)
  static class WebsocketListener {
    
    @Bean
    @ConditionalOnMissingBean(WebsocketCollector.class)
    public WebsocketCollector websocketCollector() {
      return new WebsocketCollector();
    }
  }
}

WebsocketListener: 作为 DataSyncConfiguration 的内部类, 负责 websocket 监听器初始化.


WebsocketCollector: 监听 websocket 连接及接收信息, 维护所有连接后台的 session 会话, 提供 send() 方法通知 session 信息.




网关如何建立Websocket?


WebsocketSyncDataConfiguration
WebsocketSyncDataService
SoulWebsocketClient
WebsocketDataHandler
AbstractDataHandler

WebsocketSyncDataConfiguration: 作为 Spring Bean 的配置工厂, 是网关端构建 Websocket 通信的入口. (独立出一个启动项目 soul-spring-boot-starter-sync-data-websocket , 供网关自由选用)

@Configuration
@ConditionalOnClass(WebsocketSyncDataService.class)
@ConditionalOnProperty(prefix = "soul.sync.websocket", name = "urls")
@Slf4j
public class WebsocketSyncDataConfiguration {
  
  // 收集所有注册为 Bean 的订阅器,  如 PluginDataSubscriber、MetaDataSubscriber、AuthDataSubscriber
  @Bean
  public SyncDataService websocketSyncDataService(final ObjectProvider<WebsocketConfig> websocketConfig, final ObjectProvider<PluginDataSubscriber> pluginSubscriber, final ObjectProvider<List<MetaDataSubscriber>> metaSubscribers, final ObjectProvider<List<AuthDataSubscriber>> authSubscribers) {
    log.info("you use websocket sync soul data.......");
    return new WebsocketSyncDataService(websocketConfig.getIfAvailable(WebsocketConfig::new), pluginSubscriber.getIfAvailable(), metaSubscribers.getIfAvailable(Collections::emptyList), authSubscribers.getIfAvailable(Collections::emptyList));
  }
  
  // soul-bootstrap 项目的配置信息中, 使用 soul.sync.websocket 配置要建立连接的后台路径
  @Bean
  @ConfigurationProperties(prefix = "soul.sync.websocket")
  public WebsocketConfig websocketConfig() {
    return new WebsocketConfig();
  }
}

WebsocketSyncDataService: 获取所有注册为 Bean 的 WebsocketConfig 以及各种 DataSubscriber 订阅器, 构建实现了 WebsocketClientSoulWebsocketClient 列表


SoulWebsocketClient: Websocket 通信类, 监听 websocket 连接及接收信息, 在接收到后台传来的信息后会通知各个订阅器.

public final class SoulWebsocketClient extends WebSocketClient {
  
  private final WebsocketDataHandler websocketDataHandler;
  
	private void handleResult(final String result) {
    WebsocketData websocketData = GsonUtils.getInstance().fromJson(result, WebsocketData.class);
    ConfigGroupEnum groupEnum = ConfigGroupEnum.acquireByName(websocketData.getGroupType());
    // 根据传入信息得到数据变更的事件类型, 如 refresh、update、delete 等
    String eventType = websocketData.getEventType();
    String json = GsonUtils.getInstance().toJson(websocketData.getData());
    websocketDataHandler.executor(groupEnum, json, eventType);
  }
}

WebsocketDataHandler: 初始化时构建各类实现 AbstractDataHandler 的数据处理类并缓存.

public class WebsocketDataHandler {
  
  // 缓存所有 DataHandler 数据变动处理类
  private static final EnumMap<ConfigGroupEnum, DataHandler> ENUM_MAP = new EnumMap<>(ConfigGroupEnum.class);

  public WebsocketDataHandler(final PluginDataSubscriber pluginDataSubscriber,
                              final List<MetaDataSubscriber> metaDataSubscribers,
                              final List<AuthDataSubscriber> authDataSubscribers) {
    ENUM_MAP.put(ConfigGroupEnum.PLUGIN, new PluginDataHandler(pluginDataSubscriber));
    ENUM_MAP.put(ConfigGroupEnum.SELECTOR, new SelectorDataHandler(pluginDataSubscriber));
    ENUM_MAP.put(ConfigGroupEnum.RULE, new RuleDataHandler(pluginDataSubscriber));
    ENUM_MAP.put(ConfigGroupEnum.APP_AUTH, new AuthDataHandler(authDataSubscribers));
    ENUM_MAP.put(ConfigGroupEnum.META_DATA, new MetaDataHandler(metaDataSubscribers));
  }

  public void executor(final ConfigGroupEnum type, final String json, final String eventType) {
    // 根据数据变动事件类型, 调用相应的 DataHandler 数据处理类
    ENUM_MAP.get(type).handle(json, eventType);
  }
}




网关数据变动调用链


实现 Websocket 通信的入口类 SoulWebsocketClient 在接到后台通信后, 调用 WebsocketDataHandlerexecutor() 方法匹配信息类型, 并调用对应的 DataHandlerhandler() 去处理信息.

SoulWebsocketClient
WebsocketDataHandler
AbstractDataHandler
PluginDataHandler
SelectorDataHandler
RuleDataHandler
AuthDataHandler
MetaDataHandler
PluginDataSubscriber
CommonPluginDataSubscriber
AuthDataSubscriber
SignAuthDataSubscriber
MetaDataSubscriber
org.dromara.soul.plugin.base.handler.PluginDataHandler

AbstractDataHandler: 实现 handler() 方法, 根据事件的类型 (如刷新、更新、创建、删除等), 调用对应事件抽象方法.

public abstract class AbstractDataHandler<T> implements DataHandler {

  // 根据数据的事件类型 (eventType) 分发到各自方法, 这些被调用的方法由子类实现, 因为不同类型的元数据处理类的处理方式不同
  @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;
      }
    }
  }
}

XXXDataHandler: 这里指的是 AbstractDataHandler 的各个实现类 (如 PluginDataHandler 等), 主要作用是调用其订阅器.

不同的 DataHandler 调用的订阅方法不同:

  • PluginDataHandler 会调用 onSubscribe() 通知插件元数据变更
  • SelectorDataHandler 会调用 onSelectorSubscribe() 通知选择器元数据变更
  • RuleDataHandler 会调用 onRuleSubscribe() 通知规则元数据变更
@RequiredArgsConstructor
public class PluginDataHandler extends AbstractDataHandler<PluginData> {
  
  private final PluginDataSubscriber pluginDataSubscriber;
  
  @Override
  protected void doUpdate(final List<PluginData> dataList) {
    // 调用订阅器的 onSubscribe(), 发送数据对象 PluginData
    dataList.forEach(pluginDataSubscriber::onSubscribe);
  }
  
  // ...
}

CommonPluginDataSubscriber: 订阅器的 onSubscribe() 方法会通知到所有注入为 Bean 的 PluginDataHandler 类 (不要和前面的同名类混淆, 它是 soul-plugin-base 下的接口, 它的实现类在各个可插拔插件包)
在这里插入图片描述

public class CommonPluginDataSubscriber implements PluginDataSubscriber {
  
  // 收集所有注册为 Bean 的数据处理器并缓存, 比如 HTTP 插件 divide 下的 DividePluginDataHandler
  private final Map<String, PluginDataHandler> handlerMap;
  
  // 插件元数据变动调用
  @Override
  public void onSubscribe(final PluginData pluginData) {
    BaseDataCache.getInstance().cachePluginData(pluginData);
    Optional.ofNullable(handlerMap.get(pluginData.getName())).ifPresent(handler -> handler.handlerPlugin(pluginData));
  }
  
  // 选择器元数据变动调用
  @Override
  public void onSelectorSubscribe(final SelectorData selectorData) {
    BaseDataCache.getInstance().cacheSelectData(selectorData);
    Optional.ofNullable(handlerMap.get(selectorData.getPluginName())).ifPresent(handler -> handler.handlerSelector(selectorData));
  }
  
  // 规则元数据变动调用
  @Override
  public void onRuleSubscribe(final RuleData ruleData) {
    BaseDataCache.getInstance().cacheRuleData(ruleData);
    Optional.ofNullable(handlerMap.get(ruleData.getPluginName())).ifPresent(handler -> handler.handlerRule(ruleData));
  }
}




TIPS


整个大项目下存在两个同名的类 PluginDataHandler, 其中一个在项目 soul-sync-data-websocket 下, 用于通知插件元数据变更, 另一个在 soul-plugin-base 下, 用于定义各个插件的各个类型元数据更新.


总结下这两个类命名的意义, soul-sync-data-websocket 下类名的 “plugin” 指元数据的类型为插件类, soul-plugin-base 下类名的 “plugin” 指继承它的子类来自与各个可插播插件, 比如divide、dubbo插件等

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值