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 信息.
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
订阅器, 构建实现了 WebsocketClient
的 SoulWebsocketClient
列表
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
在接到后台通信后, 调用 WebsocketDataHandler
的 executor()
方法匹配信息类型, 并调用对应的 DataHandler
的 handler()
去处理信息.
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));
}
}
整个大项目下存在两个同名的类 PluginDataHandler, 其中一个在项目 soul-sync-data-websocket
下, 用于通知插件元数据变更, 另一个在 soul-plugin-base
下, 用于定义各个插件的各个类型元数据更新.
总结下这两个类命名的意义, soul-sync-data-websocket
下类名的 “plugin” 指元数据的类型为插件类, soul-plugin-base
下类名的 “plugin” 指继承它的子类来自与各个可插播插件, 比如divide、dubbo插件等