简介
上一篇中,我们在soul-admin和soul-bootstarp中分别开启了http数据同步开关,并通过网关端的数据同步核心类CommonPluginDataSubscriber为切入点,通过方法的调用栈一步步分析了http方式同步数据时,soul网关的数据通过哪几个步骤进行了处理,这一篇,我们从soul-admin端来分析一下,当soul-admin配置数据发生变化时,如何通知到soul-bootstarp。
源码分析
首先,观察一下soul-admin在开启http数据同步时,启动后日志输出些什么,可以看到,输出如下日志:
2021-01-27 22:09:55.327 INFO 30456 --- [-long-polling-1] a.l.h.HttpLongPollingDataChangedListener : http sync strategy refresh config start.
通过观察日志,可以看到这里打印出来启用http通过方式,并且看到打印HttpLongPollingDataChangedListener这个类,通过名字就能知道这个类一定是跟http长轮询密切相关的类,打开这个类,找到日志输出的位置,代码如下:
public class HttpLongPollingDataChangedListener extends AbstractDataChangedListener {
...
protected void afterInitialize() {
long syncInterval = httpSyncProperties.getRefreshInterval().toMillis();
// Periodically check the data for changes and update the cache
scheduler.scheduleWithFixedDelay(() -> {
log.info("http sync strategy refresh config start.");
try {
this.refreshLocalCache();
log.info("http sync strategy refresh config success.");
} catch (Exception e) {
log.error("http sync strategy refresh config error!", e);
}
}, syncInterval, syncInterval, TimeUnit.MILLISECONDS);
log.info("http sync strategy refresh interval: {}ms", syncInterval);
}
...
}
可以看到,这个方法是类初始化结束之后调用的,所以我们来看看这个类是被谁初始化的,通过alt+F7跟踪HttpLongPollingDataChangedListener这个类的构造函数,发现是soul-admin模块的DataSyncConfiguration类在启动自动装配时创建了HttpLongPollingDataChangedListener这个类,如下:
@Configuration
public class DataSyncConfiguration {
...
@Configuration
@ConditionalOnProperty(name = "soul.sync.http.enabled", havingValue = "true")
@EnableConfigurationProperties(HttpSyncProperties.class)
static class HttpLongPollingListener {
@Bean
@ConditionalOnMissingBean(HttpLongPollingDataChangedListener.class)
public HttpLongPollingDataChangedListener httpLongPollingDataChangedListener(final HttpSyncProperties httpSyncProperties) {
return new HttpLongPollingDataChangedListener(httpSyncProperties);
}
}
...
}
下面来简单梳理一下soul-admin启动后,做了哪些和http同步相关的操作,流程图如下:
接下来,我们通过修改soul-admin管理端的配置数据,来观察一下会发生什么,我们对divide插件中的选择器规则记录做修改,如下红框所示:
点击提交后,观察soul-admin管理端的日志,可以看到如下日志:
2021-01-27 22:06:33.603 INFO 30456 --- [0.0-9095-exec-1] o.d.s.a.l.AbstractDataChangedListener : update config cache[RULE], old: {group='RULE', md5='16bb0120371106a1ab73561b32fe2d08', lastModifyTime=1611756295306}, updated: {group='RULE', md5='0573478feec89edb917c0313d799507d', lastModifyTime=1611756393603}
2021-01-27 22:06:33.635 INFO 30456 --- [-long-polling-1] a.l.h.HttpLongPollingDataChangedListener : send response with the changed group,ip=127.0.0.1, group=RULE, changeTime=1611756393631
从日志中可以看到,打印出来更新RULE缓存,还看到send response with the changed group这个信息,应该是讲数据变动发送给soul网关的信号,接下来我们从这两个日志作为切入点观察一下配置数据变动时,soul-admin做了什么,我们打开HttpLongPollingDataChangedListener这个类,搜索一下send response with the changed group这个日志,如下:
public void doLongPolling(final HttpServletRequest request, final HttpServletResponse response) {
...
// response immediately.
if (CollectionUtils.isNotEmpty(changedGroup)) {
this.generateResponse(response, changedGroup);
log.info("send response with the changed group, ip={}, group={}", clientIp, changedGroup);
return;
}
...
}
可以看到是调用了doLongPolling这个方法,接下来再看看是哪里调用了这个方法,通过调用方法栈可以看到是ConfigController这个类的listener方法中对doLongPolling进行了调用,而且这个ConfigController类还使用了@ConditionalOnBean(HttpLongPollingDataChangedListener.class)这个注解和HttpLongPollingDataChangedListener类产生关联,如下:
@ConditionalOnBean(HttpLongPollingDataChangedListener.class)
@RestController
@RequestMapping("/configs")
@Slf4j
public class ConfigController {
...
@PostMapping(value = "/listener")
public void listener(final HttpServletRequest request, final HttpServletResponse response) {
longPollingListener.doLongPolling(request, response);
}
...
}
这里看起来已经是入口了,我们再看看另外一个日志update config cache,打开AbstractDataChangedListener这个类,可以看到是updateCache方法打印出来的,如下:
protected <T> void updateCache(final ConfigGroupEnum group, final List<T> data) {
String json = GsonUtils.getInstance().toJson(data);
ConfigDataCache newVal = new ConfigDataCache(group.name(), json, Md5Utils.md5(json), System.currentTimeMillis());
ConfigDataCache oldVal = CACHE.put(newVal.getGroup(), newVal);
log.info("update config cache[{}], old: {}, updated: {}", group, oldVal, newVal);
}
接着再看看是哪里调用这个方法,是AbstractDataChangedListener这个类的updateSelectorCache方法调用的,继续跟,是自身的onSelectorChanged这个方法进行调用,再继续跟,发现是这个类DataChangedEventDispatcher的onApplicationEvent方法进行了调用,通过类比websocket的数据同步流程,我们可以大胆的猜想是soul-admin启动后,DataChangedEventDispatcher对所有类型的数据变动做监听,出现数据变动时,通过ConfigController这个类发送数据变动信息到soul网关,流程大致如下:
总结
这一篇我们从soul-admin的角度大致分析了一下在soul-admin配置数据发生变化时,soul-admin缓存数据发生的变化以及如何发起数据同步请求到soul-bootstarp,明天再仔细分析下如何通过http长轮询的机制是如何的。