本篇开始研究 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 同步策略的变动通知机制,期待惊喜。