本篇開始研究 Soul 網關 http 數據同步,將分爲三篇進行分析:java
但願三篇完結後能對 Soul 的 http 數據同步策略有所收穫。spring
本篇旨在探究 soul-admin
端在發起變動通知前所作的處理。json
不一樣數據變動的處理模式應當是一致的,故本篇以 selector 配置變動爲切入點進行深刻。緩存
找到 SelectorController,這是 selector 配置變動的入口app
其持有一個 SelectorService 引用,經過 SelectorService 實現 selector 配置變動。ide
再來看看 SelectorService,實現了配置變動的具體處理。微服務
其內部持有5個 mapper、1個 eventPublisher和1個 upstreamCheckService,對外提供一系列對 selector 的crud方法性能
注意 createOrUpdate 方法ui
public int createOrUpdate(final SelectorDTO selectorDTO) { int selectorCount; SelectorDO selectorDO = SelectorDO.buildSelectorDO(selectorDTO); List<SelectorConditionDTO> selectorConditionDTOs = selectorDTO.getSelectorConditions(); // 數據落庫 if (StringUtils.isEmpty(selectorDTO.getId())) { selectorCount = selectorMapper.insertSelective(selectorDO); selectorConditionDTOs.forEach(selectorConditionDTO -> { selectorConditionDTO.setSelectorId(selectorDO.getId()); selectorConditionMapper.insertSelective(SelectorConditionDO.buildSelectorConditionDO(selectorConditionDTO)); }); } else { selectorCount = selectorMapper.updateSelective(selectorDO); //delete rule condition then add selectorConditionMapper.deleteByQuery(new SelectorConditionQuery(selectorDO.getId())); selectorConditionDTOs.forEach(selectorConditionDTO -> { selectorConditionDTO.setSelectorId(selectorDO.getId()); SelectorConditionDO selectorConditionDO = SelectorConditionDO.buildSelectorConditionDO(selectorConditionDTO); selectorConditionMapper.insertSelective(selectorConditionDO); }); } // 發佈 spring 事件 publishEvent(selectorDO, selectorConditionDTOs); // 更新 divide 上游服務 updateDivideUpstream(selectorDO); return selectorCount; }
處理策略是先落庫,再發布 spring 事件,最後更新 divide 上游服務this
此處涉及 spring 的事件通知機制,在此簡要說明:
ApplicationContext經過ApplicationEvent類和ApplicationListener接口提供事件處理。
若是一個bean實現ApplicationListener接口在容器中,每次一個ApplicationEvent被髮布到ApplicationContext中,這類bean就會收到這些通知。
實現Spring事件機制主要有4個類:
下面咱們看看 Soul 是如何使用 spring 的時間通知機制。
事件定義
DataChangedEvent 繼承 ApplicationEvent,提供了 DataChangedEvent(groupKey, type, source) 事件構造方法
事件監聽器
DataChangedEventDispatcher 實現了 ApplicationListener接口,藉助 onApplicationEvent 方法監聽事件
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()); } } }
該方法內按事件類型分別處理,DataChangedEventDispatcher 同時實現了 InitializingBean 接口,在初始化後完成 listeners 的注入。
上面的事件監聽處理用到 soul 的 DataChangedListener 接口
DataChangedListener 實現了不一樣類型事件的事件響應方法用於響應 DataChangedEvent 事件。
1)AbstractDataChangedListener 的 onSelectorChanged 實現:
public void onSelectorChanged(final List<SelectorData> changed, final DataEventTypeEnum eventType) { if (CollectionUtils.isEmpty(changed)) { return; } // 更新 selector 緩存 this.updateSelectorCache(); // selector 變動後處理,實現具體的變動通知 this.afterSelectorChanged(changed, eventType); }
能夠看到 selector 變動處理是先更緩存後發通知。
2)AbstractDataChangedListener 的 updateSelectorCache 實現:
protected void updateSelectorCache() { this.updateCache(ConfigGroupEnum.SELECTOR, selectorService.listAll()); }
3)AbstractDataChangedListener 的 updateCache 實現:
protected <T> void updateCache(final ConfigGroupEnum group, final List<T> data) { String json = GsonUtils.getInstance().toJson(data); ConfigDataCache newVal = new ConfigDataCache(group.name(), json, Md5Utils.md5(json), System.currentTimeMillis()); ConfigDataCache oldVal = CACHE.put(newVal.getGroup(), newVal); log.info("update config cache[{}], old: {}, updated: {}", group, oldVal, newVal); }
能夠看到最終是建立對應的 ConfigDataCache 存入 CACHE。
本篇梳理了 soul-admin
在真正發出數據變動通知前的處理脈絡,其策略是:先寫庫後更緩存,最後發出數據變動通知。
先寫庫保證數據不丟,另外在集羣部署時,其餘 soul-admin
節點也可經過瀏覽頁面時查庫保證數據一致。
意外學到 spring 的事件通知機制,soul 中的設計果然小巧精妙。
下篇,將探究 http 同步策略的變動通知機制,期待驚喜。