Soul网关源码阅读11-使用Nacos同步数据(02)

根据上一篇文章,我们知道soul-admin启动后不会自动向nacos同步数据,需要手动操作。

本篇文章分析一下soul-admin,nacos,soul-bootstrap同步数据的过程。

一、soul-admin 如何同步网关数据?

1、插件信息更新后会发布一个DataChangedEvent事件

/**
 * create or update plugin
 * @param pluginDTO {@linkplain PluginDTO}
 * @return rows
 */
@Override
@Transactional(rollbackFor = Exception.class)
public String createOrUpdate(final PluginDTO pluginDTO) {
     
    ......
    // publish change event.
    eventPublisher.publishEvent(new DataChangedEvent(ConfigGroupEnum.PLUGIN, eventType,
            Collections.singletonList(PluginTransfer.INSTANCE.mapToData(pluginDO))));
    return StringUtils.EMPTY;
}

2、由监听事件处理类 DataChangedEventDispatcher 负责调用具体的监听实现类对 DataChangedEvent事件进行处理,这里的具体实现类是NacosDataChangedListener。

org.dromara.soul.admin.listener.DataChangedEventDispatcher

DataChangedEventDispatcher初始化完成后会执行 afterPropertiesSet(),在容器中获取所有类型是DataChangedListener.class的bean


@Override
public void afterPropertiesSet() {
     
    Collection<DataChangedListener> listenerBeans = applicationContext.getBeansOfType(DataChangedListener.class).values();
    this.listeners = Collections.unmodifiableList(new ArrayList<>(listenerBeans));
}

DataChangedEventDispatcher 监听到变更事件后,会执行 onApplicationEvent,遍历所有的监听类对监听事件进行处理,这里是NacosDataChangedListener,如下图的debug。


@Override
@SuppressWarnings("unchecked")
public void onApplicationEvent(final DataChangedEvent event) {
     
    for (DataChangedListener listener : listeners) {
     
        switch (event.getGroupKey()) {
     
            ......
            case RULE:
                listener.onRuleChanged((List<RuleData>) event.getSource(), event.getEventType());
                break;
            ......
            default:
                throw new IllegalStateException("Unexpected value: " + event.getGroupKey());
        }
    }
}


3、NacosDataChangedListener 会执行 onRuleChanged,updateRuleMap 先将网关数据同步至内存,在通过publishConfig同步至nacos。

org.dromara.soul.admin.listener.nacos.NacosDataChangedListener

// 执行监听事件
@Override
public void onRuleChanged(final List<RuleData> changed, final DataEventTypeEnum eventType) {
     
    updateRuleMap(getConfig(RULE_DATA_ID));
    switch (eventType) {
     
        ......
        default:
            changed.forEach(rule -> {
     
                List<RuleData> ls = RULE_MAP
                        .getOrDefault(rule.getSelectorId(), new ArrayList<>())
                        .stream()
                        .filter(s -> !s.getId().equals(rule.getSelectorId()))
                        .sorted(RULE_DATA_COMPARATOR)
                        .collect(Collectors.toList());
                ls.add(rule);
                RULE_MAP.put(rule.getSelectorId(), ls);
            });
            break;
    }
    publishConfig(RULE_DATA_ID, RULE_MAP);
}
// 同步至内存
private void updateRuleMap(final String configInfo) {
     
    JsonObject jo = GsonUtils.getInstance().fromJson(configInfo, JsonObject.class);
    Set<String> set = new HashSet<>(RULE_MAP.keySet());
    ......
    RULE_MAP.keySet().removeAll(set);
}
// 同步至nacos
@SneakyThrows
private void publishConfig(final String dataId, final Object data) {
     
    configService.publishConfig(dataId, GROUP, GsonUtils.getInstance().toJson(data));
}


4、DataChangedEventDispatcher 、NacosDataChangedListener 类继承关系
Soul网关源码阅读11-使用Nacos同步数据(02)_第1张图片Soul网关源码阅读11-使用Nacos同步数据(02)_第2张图片
5、总结

1、例如 soul-admin 更新网关数据,发布一个DataChangedEvent事件,eventPublisher.publishEvent(new DataChangedEvent())
2、DataChangedEventDispatcher --> onApplicationEvent()方法监听事件到事件,判断监听类是 NacosDataChangedListener
3、NacosDataChangedListener --> onRuleChanged()处理事件
4、同步至内存 updateRuleMap(getConfig(RULE_DATA_ID))
5、同步至nacos publishConfig(RULE_DATA_ID, RULE_MAP)

二、soul-bootstrap 如何同步网关数据?

1、soul-bootstrap 添加了nacos依赖 soul-spring-boot-starter-sync-data-nacos,服务启动后会自动注入NacosSyncDataConfiguration

org.dromara.soul.springboot.starter.sync.data.nacos.NacosSyncDataConfiguration

NacosSyncDataService 负责读取和同步nacos网关数据

@Configuration
@ConditionalOnClass(NacosSyncDataService.class)
@ConditionalOnProperty(prefix = "soul.sync.nacos", name = "url")
@Slf4j
public class NacosSyncDataConfiguration {
     
    // 注入nacos数据同步服务
    @Bean
    public SyncDataService nacosSyncDataService(final ObjectProvider<ConfigService> configService, final ObjectProvider<PluginDataSubscriber> pluginSubscriber,
                                           final ObjectProvider<List<MetaDataSubscriber>> metaSubscribers, final ObjectProvider<List<AuthDataSubscriber>> authSubscribers) {
     
        log.info("you use nacos sync soul data.......");
        return new NacosSyncDataService(configService.getIfAvailable(), pluginSubscriber.getIfAvailable(),
                metaSubscribers.getIfAvailable(Collections::emptyList), authSubscribers.getIfAvailable(Collections::emptyList));
    }
    // 注入nacos客户端配置服务
    @Bean
    public ConfigService nacosConfigService(final NacosConfig nacosConfig) throws Exception {
     
        Properties properties = new Properties();
        ......
        return NacosFactory.createConfigService(properties);
    }
    // 注入nacos配置服务
    @Bean
    @ConfigurationProperties(prefix = "soul.sync.nacos")
    public NacosConfig nacosConfig() {
     
        return new NacosConfig();
    }
}

2、org.dromara.soul.sync.data.nacos.NacosSyncDataService

初始化会执行 start

watcherData 负责监听nacos网关数据

updatePluginMap 同步网关数据到内存

public void start() {
     
    ......
    watcherData(RULE_DATA_ID, this::updateRuleMap);
    ......
}
@SneakyThrows
private String getConfigAndSignListener(final String dataId, final Listener listener) {
     
    return configService.getConfigAndSignListener(dataId, GROUP, 6000, listener);
}
protected void watcherData(final String dataId, final OnChange oc) {
     
    Listener listener = new Listener() {
     
        @Override
        public void receiveConfigInfo(final String configInfo) {
     
            oc.change(configInfo);
        }
        ......
    };
    oc.change(getConfigAndSignListener(dataId, listener));
    LISTENERS.getOrDefault(dataId, new ArrayList<>()).add(listener);
}


3、NacosSyncDataService 类关系图
Soul网关源码阅读11-使用Nacos同步数据(02)_第3张图片
4、总结

1、soul-bootstrap 启动向容器自动注入 NacosSyncDataConfiguration
2、NacosSyncDataConfiguration 类中会向容器注入 NacosSyncDataService
3、NacosSyncDataService --> start() --> watcherData() 监听nacos,同步网关数据到内存
4、watcherData() --> updatePluginMap()

三、总结

Soul网关源码阅读11-使用Nacos同步数据(02)_第4张图片

你可能感兴趣的:(Soul,网关源码阅读)