Soul网关源码分析-17期


后台与网关数据同步 (Nacos篇)



配置 Nacos


研究 Soul 后台与网关同步前, 需要先做好本地环境准备, 重点是启动 Nacos 服务.

通用 docker 使用 Nacos 的网址: https://nacos.io/zh-cn/docs/quick-start-docker.html

  1. 首先将 nacos-docker 项目 clone 到本地

    > git clone https://github.com/nacos-group/nacos-docker.git
    
  2. 进入 nacos-docker 目录下, 执行 docker-compose

    > docker-compose -f example/standalone-derby.yaml up
    
  3. 登录 http://127.0.0.1:8848/nacos/ 账号密码皆为 nacos



配置后台


后台的配置主要是为了让 DataSyncConfiguration 配置类中的 Nacos 相关 Bean 起作用, 并且让其他同步方式的 Bean 不生效即可

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



配置网关


对于网关端的同步方式切换我们也早已轻车熟路了, 先找到网关端的 Nacos Spring boot 启动项目
在这里插入图片描述


看看它的关键配置类 NacosSyncDataConfiguration

@Configuration
@ConditionalOnClass(NacosSyncDataService.class)
@ConditionalOnProperty(prefix = "soul.sync.nacos", name = "url")
@Slf4j
public class NacosSyncDataConfiguration {

  // ...  
  @Bean
  @ConfigurationProperties(prefix = "soul.sync.nacos")
  public NacosConfig nacosConfig() {
    return new NacosConfig();
  }
}

大致知道了它所需要的配置信息, 去配置文件中完成它.

soul:
	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:

需要注意的一点是, 确认 pom 中有引入 Nacos Spring boot 启动项目

<!--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 后台无数据?


打开 Nacos 并且开启网关后, 发现 Nacos 中并没有任何数据, 尝试在网关后台点击同步刷新也依旧没有信息出现.

先检查下启动时的代码:

@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) {
      // Nacos 监听, 当触发数据变动时会进去此类方法
      return new NacosDataChangedListener(configService);
    }

    @Bean
    @ConditionalOnMissingBean(NacosDataInit.class)
    public NacosDataInit nacosDataInit(final ConfigService configService, final SyncDataService syncDataService) {
      // Nacos 数据初始化, 在启动时会尝试推送数据到 Nacos
      return new NacosDataInit(configService, syncDataService);
    }
  }
}

在启动网关后, Nacos 依然没有任何信息, 我们看看 NacosDataInit 在启动时做了什么事情.

public class NacosDataInit implements CommandLineRunner {

  @Override
  public void run(final String... args) {
    String pluginDataId = NacosPathConstants.PLUGIN_DATA_ID;
    String authDataId = NacosPathConstants.AUTH_DATA_ID;
    String metaDataId = NacosPathConstants.META_DATA_ID;
    // 检查数据是否存在, 都不存在则推送数据到 Nacos
    if (dataIdNotExist(pluginDataId) && dataIdNotExist(authDataId) && dataIdNotExist(metaDataId)) {
      syncDataService.syncAll(DataEventTypeEnum.REFRESH);
    }
  }

  @SneakyThrows
  private boolean dataIdNotExist(final String pluginDataId) {
    String group = NacosPathConstants.GROUP;
    long timeout = NacosPathConstants.DEFAULT_TIME_OUT;
    // 从 Nacos 中获得相关数据
    final String config = configService.getConfig(pluginDataId, group, timeout);
    return config == null;
  }
}

这里有个关键接口 CommandLineRunner , 这是 SpringBoot 的机制, 即启动时执行并仅会执行一次 run() .


这里我们看到网关后台启动后尝试获取 Nacos 的相关数据, 只要存在任何类型的数据信息, 则不推送信息到 Nacos, 反之则全量推送.


那么, 为什么在同步到 Nacos 后, 却没有看到任何数据信息呢?

首先我们确信后台和 Nacos 通信是畅通的, 且也确实 debug 到推送的信息. 最关键的是, 二次启动时也在 configService.getConfig(pluginDataId, group, timeout); 处获取到了相关数据.


那么我猜测, Nacos 中是存在值的, 仅仅是隐藏了, 注意到 Nacos 是区分 namespace 的, 我们回到一开始后台的 yml 配置:

nacos:
	url: localhost:8848
  namespace: 1c10d748-af86-43b9-8265-75f487d20c6c

其中的这个 namespace 是对应 Nacos 命名空间的 ID, 我们看到 Nacos 后台中根本没有这个命名空间, 所以也看不到我们同步过去的数据.


那么怎么办呢? 在 Nacos 后台新建对应我们配置的 namespace 即可
在这里插入图片描述

接下来就可以在 Nacos 中看到所有 Soul 后台同步过去的数据啦!
在这里插入图片描述在这里插入图片描述

PS: 即使不新增命名空间, 也是能正常使用的, 因为通过 API 拿去 Nacos 的信息完全没问题, 要想显式的看还是需要手动新增命名空间的



启动网关验证同步


通过配置类 NacosSyncDataConfiguration, 找到启动网关后监听 Nacos 的 NacosSyncDataService

public class NacosSyncDataService extends NacosCacheHandler implements AutoCloseable, SyncDataService {
  
  // 初始化
	public NacosSyncDataService(final ConfigService configService, final PluginDataSubscriber pluginDataSubscriber,
                                final List<MetaDataSubscriber> metaDataSubscribers, final List<AuthDataSubscriber> authDataSubscribers) {

    super(configService, pluginDataSubscriber, metaDataSubscribers, authDataSubscribers);
    start();
  }
  
  // 监听相关数据类型
  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() {
      @Override
      public void receiveConfigInfo(final String configInfo) {
        // 当 Nacos 下数据发生变动时, 这里会被触发, 通知数据变化
        oc.change(configInfo);
      }

      @Override
      public Executor getExecutor() {
        return null;
      }
    };
    oc.change(getConfigAndSignListener(dataId, listener));
  }
}

一路追溯到 NacosCacheHandler 中

protected void updatePluginMap(final String configInfo) {
  try {
    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);
  }
}

最后, 我们在 watcherData()receiveConfigInfo() 回调监听方法处断点, 并变更 Soul 后台的信息, 看看是否走到这里
在这里插入图片描述

配置成功~

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值