【soul-boostrap】如何更新数据
上节第3步开启了如下配置:
@Configuration
@ConditionalOnClass(NacosSyncDataService.class)
@ConditionalOnProperty(prefix = "soul.sync.nacos", name = "url")
@Slf4j
public class NacosSyncDataConfiguration {
/**
* Nacos sync data service.
*
* @param configService the config service
* @param pluginSubscriber the plugin subscriber
* @param metaSubscribers the meta subscribers
* @param authSubscribers the auth subscribers
* @return the sync data service
*/
@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 config service config service.
*
* @param nacosConfig the nacos config
* @return the config service
* @throws Exception the exception
*/
@Bean
public ConfigService nacosConfigService(final NacosConfig nacosConfig) throws Exception {
Properties properties = new Properties();
if (nacosConfig.getAcm() != null && nacosConfig.getAcm().isEnabled()) {
properties.put(PropertyKeyConst.ENDPOINT, nacosConfig.getAcm().getEndpoint());
properties.put(PropertyKeyConst.NAMESPACE, nacosConfig.getAcm().getNamespace());
properties.put(PropertyKeyConst.ACCESS_KEY, nacosConfig.getAcm().getAccessKey());
properties.put(PropertyKeyConst.SECRET_KEY, nacosConfig.getAcm().getSecretKey());
} else {
properties.put(PropertyKeyConst.SERVER_ADDR, nacosConfig.getUrl());
properties.put(PropertyKeyConst.NAMESPACE, nacosConfig.getNamespace());
}
return NacosFactory.createConfigService(properties);
}
/**
* Http config http config.
*
* @return the http config
*/
@Bean
@ConfigurationProperties(prefix = "soul.sync.nacos")
public NacosConfig nacosConfig() {
return new NacosConfig();
}
}
Nacos数据同步操作如下:
public class NacosSyncDataService extends NacosCacheHandler implements AutoCloseable, SyncDataService {
/**
* Instantiates a new Nacos sync data service.
*
* @param configService the config service
* @param pluginDataSubscriber the plugin data subscriber
* @param metaDataSubscribers the meta data subscribers
* @param authDataSubscribers the auth data subscribers
*/
public NacosSyncDataService(final ConfigService configService, final PluginDataSubscriber pluginDataSubscriber,
final List<MetaDataSubscriber> metaDataSubscribers, final List<AuthDataSubscriber> authDataSubscribers) {
super(configService, pluginDataSubscriber, metaDataSubscribers, authDataSubscribers);
start();
}
/**
* 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);
}
@Override
public void close() {
LISTENERS.forEach((dataId, lss) -> {
lss.forEach(listener -> getConfigService().removeListener(dataId, GROUP, listener));
lss.clear();
});
LISTENERS.clear();
}
}
Nacos watch操作如下:
public class NacosCacheHandler {
protected static final String GROUP = "DEFAULT_GROUP";
protected static final String PLUGIN_DATA_ID = "soul.plugin.json";
protected static final String SELECTOR_DATA_ID = "soul.selector.json";
protected static final String RULE_DATA_ID = "soul.rule.json";
protected static final String AUTH_DATA_ID = "soul.auth.json";
protected static final String META_DATA_ID = "soul.meta.json";
protected static final Map<String, List<Listener>> LISTENERS = Maps.newConcurrentMap();
@Getter
private final ConfigService configService;
private final PluginDataSubscriber pluginDataSubscriber;
private final List<MetaDataSubscriber> metaDataSubscribers;
private final List<AuthDataSubscriber> authDataSubscribers;
public NacosCacheHandler(final ConfigService configService, final PluginDataSubscriber pluginDataSubscriber,
final List<MetaDataSubscriber> metaDataSubscribers,
final List<AuthDataSubscriber> authDataSubscribers) {
this.configService = configService;
this.pluginDataSubscriber = pluginDataSubscriber;
this.metaDataSubscribers = metaDataSubscribers;
this.authDataSubscribers = authDataSubscribers;
}
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);
}
}
protected void updateSelectorMap(final String configInfo) { // 更新选择器数据
try {
List<SelectorData> selectorDataList = GsonUtils.getInstance().toObjectMapList(configInfo, SelectorData.class).values().stream().flatMap(Collection::stream).collect(Collectors.toList());
selectorDataList.forEach(selectorData -> Optional.ofNullable(pluginDataSubscriber).ifPresent(subscriber -> {
subscriber.unSelectorSubscribe(selectorData);
subscriber.onSelectorSubscribe(selectorData);
}));
} catch (JsonParseException e) {
log.error("sync selector data have error:", e);
}
}
protected void updateRuleMap(final String configInfo) {
try {
List<RuleData> ruleDataList = GsonUtils.getInstance().toObjectMapList(configInfo, RuleData.class).values()
.stream().flatMap(Collection::stream)
.collect(Collectors.toList());
ruleDataList.forEach(ruleData -> Optional.ofNullable(pluginDataSubscriber).ifPresent(subscriber -> {
subscriber.unRuleSubscribe(ruleData);
subscriber.onRuleSubscribe(ruleData);
}));
} catch (JsonParseException e) {
log.error("sync rule data have error:", e);
}
}
protected void updateMetaDataMap(final String configInfo) {
try {
List<MetaData> metaDataList = new ArrayList<>(GsonUtils.getInstance().toObjectMap(configInfo, MetaData.class).values());
metaDataList.forEach(metaData -> metaDataSubscribers.forEach(subscriber -> {
subscriber.unSubscribe(metaData);
subscriber.onSubscribe(metaData);
}));
} catch (JsonParseException e) {
log.error("sync meta data have error:", e);
}
}
protected void updateAuthMap(final String configInfo) {
try {
List<AppAuthData> appAuthDataList = new ArrayList<>(GsonUtils.getInstance().toObjectMap(configInfo, AppAuthData.class).values());
appAuthDataList.forEach(appAuthData -> authDataSubscribers.forEach(subscriber -> {
subscriber.unSubscribe(appAuthData);
subscriber.onSubscribe(appAuthData);
}));
} catch (JsonParseException e) {
log.error("sync auth data have error:", e);
}
}
@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);
}
@Override
public Executor getExecutor() {
return null;
}
};
oc.change(getConfigAndSignListener(dataId, listener));
LISTENERS.getOrDefault(dataId, new ArrayList<>()).add(listener); // 添加一个监听器,对数据进行更新
}
protected interface OnChange {
void change(String changeData);
}
}
Nacos 的数据基本都是采用json来进行数据同步的。数据的更新完全是采用全量式的更新,更新消耗的网络资源也会比较大。