本次分析在0125号萧大佬修复了:当Nacos数据是空的时候,soul-admin不会初始化同步数据到nacos,问题之后。
soul-admin 如何同步网关数据
-
这块的数据更新其实类似zookeeper、websocket。
-
soul-admin数据初始化全量更新,在
DataSyncConfiguration
类的内部类监听NacosListener
@Configuration public class DataSyncConfiguration { //....... @Configuration @ConditionalOnProperty(prefix = "soul.sync.nacos", name = "url") @Import(NacosConfiguration.class) static class NacosListener { @Bean @ConditionalOnMissingBean(NacosDataChangedListener.class) public DataChangedListener nacosDataChangedListener(final ConfigService configService) { return new NacosDataChangedListener(configService); } @Bean @ConditionalOnMissingBean(NacosDataInit.class) public NacosDataInit nacosDataInit(final ConfigService configService, final SyncDataService syncDataService) { return new NacosDataInit(configService, syncDataService); } }
-
ZookeeperDataInit
的 run 方法,判断其数据节点是否存在,如果不存在,则调用同步数据SyncDataServiceImpl#syncAll
方法public void run(final String... args) { String pluginPath = ZkPathConstants.PLUGIN_PARENT; String authPath = ZkPathConstants.APP_AUTH_PARENT; String metaDataPath = ZkPathConstants.META_DATA; if (!zkClient.exists(pluginPath) && !zkClient.exists(authPath) && !zkClient.exists(metaDataPath)) { syncDataService.syncAll(DataEventTypeEnum.REFRESH); } }
-
发送了五种类型数据事件,看这里
ApplicationEventPublisher
发布了一个订阅DataChangedEvent
,这边有一套spring的事件通知机制:这个DataChangedEvent
继承了ApplicationEvent
,DataChangedEventDispatcher
(事件分发器)实现了ApplicationListener
,DataChangedEventDispatcher初始化完成后会执行 afterPropertiesSet(),在容器中获取所有类型是DataChangedListener
.class的bean, 就找到了DataChangedListener
接口,再找到实现类NacosDataChangedListener
,下面大概说明。
@Override
public boolean syncAll(final DataEventTypeEnum type) {
appAuthService.syncData();
List<PluginData> pluginDataList = pluginService.listAll();
eventPublisher.publishEvent(new DataChangedEvent(ConfigGroupEnum.PLUGIN, type, pluginDataList));
List<SelectorData> selectorDataList = selectorService.listAll();
eventPublisher.publishEvent(new DataChangedEvent(ConfigGroupEnum.SELECTOR, type, selectorDataList));
List<RuleData> ruleDataList = ruleService.listAll();
eventPublisher.publishEvent(new DataChangedEvent(ConfigGroupEnum.RULE, type, ruleDataList));
metaDataService.syncData();
return true;
}
@Override
public void afterPropertiesSet() {
Collection<DataChangedListener> listenerBeans = applicationContext.getBeansOfType(DataChangedListener.class).values();
this.listeners = Collections.unmodifiableList(new ArrayList<>(listenerBeans));
}
-
DataChangedEventDispatcher
监听到变更事件后,会执行 onApplicationEvent,遍历所有的监听类对监听事件进行处理,这里是NacosDataChangedListener
public void onApplicationEvent(final DataChangedEvent event) { for (DataChangedListener listener : listeners) { switch (event.getGroupKey()) { // ...... case META_DATA: listener.onMetaDataChanged((List<MetaData>) event.getSource(), event.getEventType()); break; default: throw new IllegalStateException("Unexpected value: " + event.getGroupKey()); } } }
-
NacosDataChangedListener
会执行 onSelectorChanged,updateSelectorMap先将网关数据同步至内存SELECTOR_MAP,在通过publishConfig同步至nacos。public void onSelectorChanged(final List<SelectorData> changed, final DataEventTypeEnum eventType) { updateSelectorMap(getConfig(NacosPathConstants.SELECTOR_DATA_ID)); switch (eventType) { // ...... default: changed.forEach(selector -> { List<SelectorData> ls = SELECTOR_MAP .getOrDefault(selector.getPluginName(), new ArrayList<>()) .stream() .filter(s -> !s.getId().equals(selector.getId())) .sorted(SELECTOR_DATA_COMPARATOR) .collect(Collectors.toList()); ls.add(selector); SELECTOR_MAP.put(selector.getPluginName(), ls); }); break; } publishConfig(NacosPathConstants.SELECTOR_DATA_ID, SELECTOR_MAP); }
总结:
1、soul-admin 更新网关数据,发布一个DataChangedEvent
事件,eventPublisher.publishEvent(new DataChangedEvent())。
2、DataChangedEventDispatcher
--> onApplicationEvent()方法监听事件,初始化完成后会执行 afterPropertiesSet(),监听接口是DataChangedListener
实现类是 NacosDataChangedListener
。
3、NacosDataChangedListener
--> onSelectorChanged()处理事件。
4、同步至内存 updateSelectorMap(getConfig(NacosPathConstants.SELECTOR_DATA_ID))。
5、publishConfig(NacosPathConstants.SELECTOR_DATA_ID, SELECTOR_MAP)。