摘自:https://www.cnblogs.com/qishun/p/14337879.html
Soul 网关 Nacos 数据同步源码解析
学习目标:
学习Soul 网关 Nacos 数据同步源码解析
学习内容:
- 环境配置
- Soul 网关 Nacos 数据同步基本概念
- 源码分析
学习时间:2020年1月28号 早7点
学习产出:
环境配置:
- 引入依赖
在 soul-bootstrap 项目的 pom.xml 文件中引入了 soul-spring-boot-starter-sync-data-nacos 这个 starter 。
<dependency>
<groupId>org.dromara</groupId>
<artifactId>soul-spring-boot-starter-sync-data-nacos</artifactId>
<version>${last.version}</version>
</dependency>
- 环境配置
在 soul-bootstrap 项目的 application-local.yml 文件中,配置
soul :
sync:
nacos:
url: localhost:8848
namespace: 1c10d748-af86-43b9-8265-75f487d20c6c
acm:
enabled: false
endpoint: acm.aliyun.com
namespace:
accessKey:
secretKey:
#url: 配置成你的nacos地址,集群环境请使用(,)分隔。
在 soul-admin 项目中的 application.yml 文件中配置 nacos 同步的相关配置如下:
soul:
sync:
nacos:
url: localhost:8848
namespace: 7aba82c9-426b-4d72-89c9-060d9af63e14
# 此处为前文中提到的命名空间ID或命名空间名称 soul
Nacos 的关键特性
服务发现和服务健康监测
动态配置服务
动态 DNS 服务
服务及其元数据管理
Nacos 中的几个概念
命名空间(Namespace): 不同环境的配置隔离
配置分组(Group): 不同的服务可以归类到同一分组。一般将一个项目的配置分到一组
配置集(Data ID) : 一个配置文件通常就是一个配置集
- nacos同步策略-源码追踪
从 soul-bootstrap 开始追踪
NacosSyncDataConfiguration 这个类加载了 soul.sync.nacos 这段配置。该类创建了 nacosSyncDataService 。
@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));
}
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);
}
进入 watcherData 方法,此时我们会进入一个重要的类 NacosCacheHandler 。
// 即便对 lambda 不熟悉,我们也可以大致推测,这里的功能应该是通过调用updateXxxMap方法,对元数据、插件、选择器等进行监听
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.computeIfAbsent(dataId, key -> new ArrayList<>()).add(listener);
}
protected interface OnChange {
void change(String changeData);
}
updatePluginMap 方法:
protected void updatePluginMap(final String configInfo) {
try {
// Fix bug #656(https://github.com/dromara/soul/issues/656) 此处解决了一个 nacos data sync error 的 bug
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);
}
}
追踪一下 unSubscribe(pluginData) 和 onSubscribe(pluginData) ,进入 CommonPluginDataSubscriber 中:
@Override
public void onSubscribe(final PluginData pluginData) {
subscribeDataHandler(pluginData, DataEventTypeEnum.UPDATE);
}
@Override
public void unSubscribe(final PluginData pluginData) {
subscribeDataHandler(pluginData, DataEventTypeEnum.DELETE);
}
// 根据传入的数据类型ID,和数据处理类型,调用相应的处理函数,看具体是执行update更新还是delete删除
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);
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));
}
}
});
}
admin追踪:
是 DataSyncConfiguration 这个类加载了 soul.sync.nacos 这段配置。该类创建了 NacosDataChangedListener 。
/**
* The type Nacos listener.
*/
@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);
}
/**
* Nacos data init zookeeper data init.
*
* @param configService the config service
* @param syncDataService the sync data service
* @return the nacos data init
*/
@Bean
@ConditionalOnMissingBean(NacosDataInit.class)
public NacosDataInit nacosDataInit(final ConfigService configService, final SyncDataService syncDataService) {
return new NacosDataInit(configService, syncDataService);
}
}
@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;
if (dataIdNotExist(pluginDataId) && dataIdNotExist(authDataId) && dataIdNotExist(metaDataId)) {
syncDataService.syncAll(DataEventTypeEnum.REFRESH);
}
}
// type 是 REFRESH
@Override
public boolean syncAll(final DataEventTypeEnum type) {
appAuthService.syncData();
List<PluginData> pluginDataList = pluginService.listAll();
eventPublisher.publishEvent(new DataChangedEvent(ConfigGroupEnum.PLUGIN, type, pluginDataList));
List<SelectorData> selectorDataList = selectorService.listAll();
eventPublisher.publishEvent(new DataChangedEvent(ConfigGroupEnum.SELECTOR, type, selectorDataList));
List<RuleData> ruleDataList = ruleService.listAll();
eventPublisher.publishEvent(new DataChangedEvent(ConfigGroupEnum.RULE, type, ruleDataList));
metaDataService.syncData();
return true;
}
public static void send(final String message, final DataEventTypeEnum type) {
if (StringUtils.isNotBlank(message)) {
if (DataEventTypeEnum.MYSELF == type) {
Session session = (Session) ThreadLocalUtil.get(SESSION_KEY);
if (session != null) {
sendMessageBySession(session, message);
}
} else {
SESSION_SET.forEach(session -> sendMessageBySession(session, message));
}
}
}
设计模式之结构型装饰者模式
设计模式之结构型组合模式
设计模式之创建型建造者模式
设计模式之创建型原型模式
设计模式之创建型单例模式
设计模式之创建型抽象工厂模式
设计模式之创建型工厂模式
设计模式之创建型简单工厂模式
找出数组出现最多的元素,并返回出现的下标
- 最新文章
-
SAP Netweaver和Hybris Commerce启动后执行的默认操作
SAP UI configuration determination的优先级
SAP附件UI里选择的文件是如何传到ABAP服务器的
如何在SAP Cloud for Customer里开发具有依赖关系的互动下拉列表
如何为SAP API Portal上创建的API增添API key验证保护功能
使用SAP WebIDE消费API Portal里创建的API时的错误消息
在SAP云平台的API portal里创建和管理API
SAP UI5应用里搜索功能的实现
SAP UI5 StandardListItem和ObjectListItem的区别
SAP CRM和Cloud for Customer的扩展字段元数据
Copyright © 2011-2022 走看看