目標
- 數(shù)據(jù)同步原理分析
- 動態(tài)數(shù)據(jù)流示意
- 源碼解析
數(shù)據(jù)同步原理分析
在1.x版本中,配置服務(wù)依賴zk實現(xiàn),管理將變更信息push給網(wǎng)關(guān)。而2.x版本支websocket、http、zk、nacos,通過soul.sync.strategy 指定對應(yīng)的同步策略,默認使websocket同步策略,可以做到秒級數(shù)據(jù)同步,但是soul-admin與soul-bootstrap必須使用相同的同步策略。
soul-admin 在用戶發(fā)生配置變更之后,會通過EventPublisher發(fā)出配置變更通知,由EventDispatcher處理該變更通知。然后根據(jù)配置的同步策略(http、websocket、zk、nacos),將配置發(fā)送到對應(yīng)的事件處理器上。本次分析的是websocket,則將變更數(shù)據(jù)主動推送到soul-bootstrap,并且在網(wǎng)關(guān)層會有WebSocketDataChangedListener來處理admin的數(shù)據(jù)推送
動態(tài)數(shù)據(jù)流示意
從上圖可以看出幾個關(guān)鍵的類 DataChangeEvent(發(fā)送事件數(shù)據(jù)載體),ApplicationListener<T Extends ApplicationEvent>(Interface to be implemented by application event listeners.),DataChangedListener(監(jiān)聽器接口)
源碼解析
soul-admin 數(shù)據(jù)發(fā)生改變發(fā)送數(shù)據(jù)變更通知
這里我是用Selector來進行模擬
// 選擇器變更發(fā)送事件,事件類型統(tǒng)一封裝在DataChangeEvent對象
private void publishEvent(final SelectorDO selectorDO, final List<SelectorConditionDTO> selectorConditionDTOs) {
PluginDO pluginDO = pluginMapper.selectById(selectorDO.getPluginId());
List<ConditionData> conditionDataList =
selectorConditionDTOs.stream().map(ConditionTransfer.INSTANCE::mapToSelectorDTO).collect(Collectors.toList());
// publish change event.發(fā)送 DataChangeEvent類封裝的事件包,而我們看DataChangedEvent也是實現(xiàn) ApplicationEvent
eventPublisher.publishEvent(new DataChangedEvent(ConfigGroupEnum.SELECTOR, DataEventTypeEnum.UPDATE,
Collections.singletonList(SelectorDO.transFrom(selectorDO, pluginDO.getName(), conditionDataList))));
}
DataChangedEventDispatcher 接收到事件
接收到ApplicationEventPublisher發(fā)送來的事件之后觸發(fā)onApplicationEvent執(zhí)行,拿著event.getGroupKey進行比對從listener中找到匹配的事件處理函數(shù),這里面使用了策略模式,動態(tài)根據(jù)事件類型匹配對應(yīng)的處理事件。
InitializingBean獲取listeners
此處源碼地方有可以優(yōu)化的地方,因為soul默認數(shù)據(jù)同步方式只允許有一種,所以這里無需使用list,可以根據(jù)用戶當前配置的方式進行定位出最終的listener.這樣在事件分發(fā)器那塊就無需for循環(huán)處理了。
WebSocketClient 處理事件消息
總結(jié)
到這里從用戶改變數(shù)據(jù),到事件通知,然后通過websocket將數(shù)據(jù)發(fā)送到soul網(wǎng)關(guān)端,至于數(shù)據(jù)到網(wǎng)關(guān)端處理邏輯,下一章再詳細分析。