Don’t say much, get up and do

You need to configure the NACOS first, refer to the NACOS configuration document

Soul – admin configuration

Enable data synchronization nacOS configuration for the admin module

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

Soul configuration

Enable data synchronization nacOS configuration for the Soul module

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

Admin Start configuration

In the startup configuration class 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); }}Copy the code

Inherit DataChangedListener interface as data update listener, used to listen to admin management module data changes

When the admin module has data updates, it directly publishes messages

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

NacosDataChangedListener to listen to the data update time, execute onXXXChanged() method, where XXX is the data name of plugin, Auth, selector and other different dimension

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

Soul module

In the soul – spring – the boot – the configuration class NacosSyncDataConfiguration starter module, will nacos related configuration bean into the container, including configuration synchronization data 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)); }Copy the code

NacosSyncDataService inherits the NacosCacheHandler interface and starts the listener method start() directly in the constructor.

The start() method contains gateway data of different dimensions, 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);
   }
Copy the code

The watcherData() method directly listens for nacOS data changes

Protected void watcherData(final String dataId, final OnChange OC) {// Listenner Listener Listener = new Listener() {@override public void receiveConfigInfo(Final String configInfo) { oc.change(configInfo); } @Override public Executor getExecutor() { return null; }}; Oc. change(getConfigAndSignListener(dataId, listener)); LISTENERS.getOrDefault(dataId, new ArrayList<>()).add(listener); }Copy the code

Call the data change subscription method

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 -> option. ofNullable(pluginDataSubscriber). IfPresent (subscriber -> {// The event is not subscribed subscriber.unSubscribe(pluginData); // Continue subscriber.onsubscribe (pluginData); })); } catch (JsonParseException e) { log.error("sync plugin data have error:", e); }}Copy the code

Follow the subscribe update event and perform a specific data synchronization update in Soul, that is, update the cache of soul.

private <T> void subscribeDataHandler(final T classData, final DataEventTypeEnum dataType) { Optional.ofNullable(classData).ifPresent(data -> { if (data instanceof PluginData) {  PluginData pluginData = (PluginData) data; / / the plugin UPDATE events if (dataType = = DataEventTypeEnum. UPDATE) {BaseDataCache. GetInstance (). CachePluginData (pluginData); // The hander implements the PluginDataHandler interface, depending on the implementation class, Optional.ofnullable (handlermap.get (plugindata.getName ()))).ifpresent (handler -> pluginData.getName()) handler.handlerPlugin(pluginData)); / / DELETE the plugin event} 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)); }}}); } ` `Copy the code