使用 nacos 进行数据同步时,首先 soul-admin 的 application.yml 文件配置使用 nacos 同步

  sync:
#    websocket:
#      enabled: true
#      zookeeper:
#          url: localhost:2181
#          sessionTimeout: 5000
#          connectionTimeout: 2000
#      http:
#        enabled: true
      nacos:
        url: localhost:8848
        namespace: 1c10d748-af86-43b9-8265-75f487d20c6c
  #      acm:
  #        enabled: false
  #        endpoint: acm.aliyun.com
  #        namespace:
  #        accessKey:
  #        secretKey:

soul-bootstrap application-local.yml 也配置下

soul:
    file:
      enabled: true
    corss:
      enabled: true
    dubbo :
      parameter: multi
    sync:
#        websocket :
#             urls: ws://localhost:9095/websocket
#        zookeeper:
#             url: localhost:2181
#             sessionTimeout: 5000
#             connectionTimeout: 2000
#        http:
#             url : http://localhost:9095
        nacos:
          url: localhost:8848
          namespace: 1c10d748-af86-43b9-8265-75f487d20c6c
#          acm:
#            enabled: false
#            endpoint: acm.aliyun.com
#            namespace:
#            accessKey:
#            secretKey:

最最重要的是 soul-bootstrap 的 pom.xml 文件,需要引入 nacos 同步的 starter

<!--soul data sync start use nacos-->
<dependency>
    <groupId>org.dromara</groupId>
    <artifactId>soul-spring-boot-starter-sync-data-nacos</artifactId>
    <version>${project.version}</version>
</dependency>

接着启动本地 nacos 服务,启动完 soul-admin,soul-bootstrap 后,最新版本,第一次启动,数据可以同步到 nacos的后台,此时登录 nacos 后端,就有了我们需要的数据。如果你还是没有数据,先去 nacos 后台命名空间那里新建一个命名空间再启动项目,名字就是 yml 文件配置的 namespace。

启动 soul-admin时,NacosDataChangedListener 创建了 configService ,作为服务端。

当启动 soul-bootstrap 时,会加载 NacosSyncDataService 类,这里会执行下面的 start 方法。

这一块代码确实很难懂,就以第一行为例,updatePluginMap方法还是需要参数的,我一开始没看懂是哪里传参的,后来加上断点,debug的时候,才搞懂流程。首先去执行 watcherData 方法,新建一个 listener(就可以监听到 soul-admin的数据变化),下面的 oc.change 就是去执行 updatePluginMap 方法,参数是从 getConfigAndSignListener(dataId, listener) 获取的,从nacos 配置中心拿数据,当然一开始是空的,默认是 ‘{}’,updatePluginMap 这个方法就是拿这个数据去同步到内存中了。

public void start() {
        watcherData(PLUGIN_DATA_ID, this::updatePluginMap);
        watcherData(SELECTOR_DATA_ID, this::updateSelectorMap);
        watcherData(RULE_DATA_ID, this::updateRuleMap);
        watcherData(META_DATA_ID, this::updateMetaDataMap);
        watcherData(AUTH_DATA_ID, this::updateAuthMap);
}

protected void watcherData(final String dataId, final OnChange oc) {
        Listener listener = new Listener() {
            //接收 soul-admin 的数据变化
            @Override
            public void receiveConfigInfo(final String configInfo) {
                oc.change(configInfo);
            }

            @Override
            public Executor getExecutor() {
                return null;
            }
        };
    	//执行 updatePluginMap 方法,getConfigAndSignListener(dataId, listener) 从配置中心获取数据
        oc.change(getConfigAndSignListener(dataId, listener));
        LISTENERS.computeIfAbsent(dataId, key -> new ArrayList<>()).add(listener);
}

protected void updatePluginMap(final String configInfo) {
        try {
            // Fix bug #656(https://github.com/dromara/soul/issues/656)
            List<PluginData> pluginDataList = new ArrayList<>(GsonUtils.getInstance().toObjectMap(configInfo, PluginData.class).values());
            pluginDataList.forEach(pluginData -> Optional.ofNullable(pluginDataSubscriber).ifPresent(subscriber -> {
                //数据更新到内存
                subscriber.unSubscribe(pluginData);
                subscriber.onSubscribe(pluginData);
            }));
        } catch (JsonParseException e) {
            log.error("sync plugin data have error:", e);
        }
}

有数据变动,soul-admin 把数据发布出去,NacosCacheHandler 的 watcherData 的 listener 接收到数据变更, 具体流程就是在 updatePluginMap 这类方法执行的了。

@SneakyThrows
//soul-admin 数据变更,发布到 nacos。
private void publishConfig(final String dataId, final Object data) {
    configService.publishConfig(dataId, GROUP, GsonUtils.getInstance().toJson(data));
}