Soul网关(10) - Nacos同步

779 阅读3分钟

话不多说,上来就干

需要先配置nacos,可以参考nacos配置文档

soul-admin配置

开启admin模块数据同步nacos配置

soul:
 sync:
   nacos:
     url: localhost:8848
     namespace: 1c10d748-af86-43b9-8265-75f487d20c6c
     acm:
       enabled: false
       endpoint: acm.aliyun.com
       namespace:
       accessKey:
       secretKey:

soul配置

开启soul模块数据同步nacos配置

soul :
 sync:
   nacos:
     url: localhost:8848
     namespace: 1c10d748-af86-43b9-8265-75f487d20c6c
     acm:
       enabled: false
       endpoint: acm.aliyun.com
       namespace:
       accessKey:
       secretKey:

admin启动配置

在启动配置类 org.dromara.soul.admin.config.DataSyncConfiguration

    @Configuration
   @ConditionalOnProperty(prefix = "soul.sync.nacos", name = "url")
   @Import(NacosConfiguration.class)
   static class NacosListener {

       /**
        * Data changed listener data changed listener.
        *
        * @param configService the config service
        * @return the data changed listener
        */
       @Bean
       @ConditionalOnMissingBean(NacosDataChangedListener.class)
       public DataChangedListener nacosDataChangedListener(final ConfigService configService) {
           return new NacosDataChangedListener(configService);
       }
   }

继承DataChangedListener接口,作为数据更新监听器,用于监听admin管理模块数据变化

当admin模块有数据更新是,直接发布消息

        eventPublisher.publishEvent(new DataChangedEvent(ConfigGroupEnum.PLUGIN, eventType,
               Collections.singletonList(PluginTransfer.INSTANCE.mapToData(pluginDO))));

NacosDataChangedListener监听到数据更新时间,执行onXXXChanged()方法,这里的xxx就是plugin、auth、selector等不同维度的数据称谓

    @Override
   public void onPluginChanged(final List<PluginData> changed, final DataEventTypeEnum eventType) {
       updatePluginMap(getConfig(PLUGIN_DATA_ID));
       //根据不同的事件类型,刷新admin模块缓存
       switch (eventType) {
           case DELETE:
               changed.forEach(plugin -> PLUGIN_MAP.remove(plugin.getName()));
               break;
           case REFRESH:
           case MYSELF:
               Set<String> set = new HashSet<>(PLUGIN_MAP.keySet());
               changed.forEach(plugin -> {
                   set.remove(plugin.getName());
                   PLUGIN_MAP.put(plugin.getName(), plugin);
               });
               PLUGIN_MAP.keySet().removeAll(set);
               break;
           default:
               changed.forEach(plugin -> PLUGIN_MAP.put(plugin.getName(), plugin));
               break;
       }
       //调用nacos发布消息方法
       publishConfig(PLUGIN_DATA_ID, PLUGIN_MAP);
   }

soul模块

soul-spring-boot-starter模块中的配置类中NacosSyncDataConfiguration,将nacos的相关配置bean注入容器,其中配置同步数据bean

    @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));
   }

NacosSyncDataService继承了NacosCacheHandler接口,在构造方法中直接开启监听方法start()

start()方法中包含了不同维度的网关数据watch

    /**
    * 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);
   }

watcherData()方法中,直接监听nacos数据变化

    protected void watcherData(final String dataId, final OnChange oc) {
       // listenner是nacos自己的监听器,用于监听nacos数据中心变化
       Listener listener = new Listener() {
           @Override
           public void receiveConfigInfo(final String configInfo) {
               oc.change(configInfo);
           }

           @Override
           public Executor getExecutor() {
               return null;
           }
       };
       // 调用change方法,执行soul自己的数据变化逻辑
       oc.change(getConfigAndSignListener(dataId, listener));
       LISTENERS.getOrDefault(dataId, 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中执行具体的数据同步更新,即更新soul的缓存(源码作者真好,这个方法中的中文注释都是源码自带的,哈哈哈~~~)

    private <T> void subscribeDataHandler(final T classData, final DataEventTypeEnum dataType) {
        Optional.ofNullable(classData).ifPresent(data -> {
            if (data instanceof PluginData) {
                PluginData pluginData = (PluginData) data;
                // 插件更新事件
                if (dataType == DataEventTypeEnum.UPDATE) {
                    BaseDataCache.getInstance().cachePluginData(pluginData);
                    //这里的hander实现PluginDataHandler接口,根据实现类不一样,进行区别化更新插件
                    Optional.ofNullable(handlerMap.get(pluginData.getName())).ifPresent(handler -> handler.handlerPlugin(pluginData));
                    //删除插件事件
                } else if (dataType == DataEventTypeEnum.DELETE) {
                    BaseDataCache.getInstance().removePluginData(pluginData);
                    Optional.ofNullable(handlerMap.get(pluginData.getName())).ifPresent(handler -> handler.removePlugin(pluginData));
                }
            } else if (data instanceof SelectorData) {
                SelectorData selectorData = (SelectorData) data;
                if (dataType == DataEventTypeEnum.UPDATE) {
                    BaseDataCache.getInstance().cacheSelectData(selectorData);
                    Optional.ofNullable(handlerMap.get(selectorData.getPluginName())).ifPresent(handler -> handler.handlerSelector(selectorData));
                } else if (dataType == DataEventTypeEnum.DELETE) {
                    BaseDataCache.getInstance().removeSelectData(selectorData);
                    Optional.ofNullable(handlerMap.get(selectorData.getPluginName())).ifPresent(handler -> handler.removeSelector(selectorData));
                }
            } else if (data instanceof RuleData) {
                RuleData ruleData = (RuleData) data;
                if (dataType == DataEventTypeEnum.UPDATE) {
                    BaseDataCache.getInstance().cacheRuleData(ruleData);
                    Optional.ofNullable(handlerMap.get(ruleData.getPluginName())).ifPresent(handler -> handler.handlerRule(ruleData));
                } else if (dataType == DataEventTypeEnum.DELETE) {
                    BaseDataCache.getInstance().removeRuleData(ruleData);
                    Optional.ofNullable(handlerMap.get(ruleData.getPluginName())).ifPresent(handler -> handler.removeRule(ruleData));
                }
            }
        });
    }
``