引言

本篇开始研究 Soul 网关 http 数据同步,将分为三篇进行分析:

  • 《Admin通知前处理》
  • 《变更通知机制》
  • 《Bootstrap处理变更通知》

希望三篇完结后能对 Soul 的 http 数据同步策略有所收获。

本篇旨在探究 soul-admin 端在发起变更通知前所做的处理。

不同数据变更的处理模式应当是一致的,故本篇以 selector 配置变更为切入点进行深入。

一、配置变更入口

找到 SelectorController,这是 selector 配置变更的入口

其持有一个 SelectorService 引用,通过 SelectorService 实现 selector 配置变更。

二、配置变更服务

再来看看 SelectorService,实现了配置变更的具体处理。

其内部持有5个 mapper、1个 eventPublisher和1个 upstreamCheckService,对外提供一系列对 selector 的crud方法

注意 createOrUpdate 方法

public int createOrUpdate(final SelectorDTO selectorDTO) {
int selectorCount;
SelectorDO selectorDO = SelectorDO.buildSelectorDO(selectorDTO);
List<SelectorConditionDTO> selectorConditionDTOs = selectorDTO.getSelectorConditions();
// 数据落库
if (StringUtils.isEmpty(selectorDTO.getId())) {
selectorCount = selectorMapper.insertSelective(selectorDO);
selectorConditionDTOs.forEach(selectorConditionDTO -> {
selectorConditionDTO.setSelectorId(selectorDO.getId());
selectorConditionMapper.insertSelective(SelectorConditionDO.buildSelectorConditionDO(selectorConditionDTO));
});
} else {
selectorCount = selectorMapper.updateSelective(selectorDO);
//delete rule condition then add
selectorConditionMapper.deleteByQuery(new SelectorConditionQuery(selectorDO.getId()));
selectorConditionDTOs.forEach(selectorConditionDTO -> {
selectorConditionDTO.setSelectorId(selectorDO.getId());
SelectorConditionDO selectorConditionDO = SelectorConditionDO.buildSelectorConditionDO(selectorConditionDTO);
selectorConditionMapper.insertSelective(selectorConditionDO);
});
}
// 发布 spring 事件
publishEvent(selectorDO, selectorConditionDTOs);
// 更新 divide 上游服务
updateDivideUpstream(selectorDO);
return selectorCount;
}

处理策略是先落库,再发布 spring 事件,最后更新 divide 上游服务

三、spring 事件通知机制

此处涉及 spring 的事件通知机制,在此简要说明:

ApplicationContext通过ApplicationEvent类和ApplicationListener接口提供事件处理。

如果一个bean实现ApplicationListener接口在容器中,每次一个ApplicationEvent被发布到ApplicationContext中,这类bean就会收到这些通知。

实现Spring事件机制主要有4个类:

  • ApplicationEvent:事件,每个实现类表示一类事件,可携带数据。
  • ApplicationListener:事件监听器,用于接收事件处理时间。
  • ApplicationEventMulticaster:事件管理者,用于事件监听器的注册和事件的广播。
  • ApplicationEventPublisher:事件发布者,委托ApplicationEventMulticaster完成事件发布。

四、soul 实现事件通知

下面我们看看 Soul 是如何使用 spring 的时间通知机制。

事件定义

DataChangedEvent 继承 ApplicationEvent,提供了 DataChangedEvent(groupKey, type, source) 事件构造方法

事件监听器

DataChangedEventDispatcher 实现了 ApplicationListener接口,借助 onApplicationEvent 方法监听事件

public void onApplicationEvent(final DataChangedEvent event) {
for (DataChangedListener listener : listeners) {
switch (event.getGroupKey()) {
case APP_AUTH:
listener.onAppAuthChanged((List<AppAuthData>) event.getSource(), event.getEventType());
break;
case PLUGIN:
listener.onPluginChanged((List<PluginData>) event.getSource(), event.getEventType());
break;
case RULE:
listener.onRuleChanged((List<RuleData>) event.getSource(), event.getEventType());
break;
case SELECTOR:
listener.onSelectorChanged((List<SelectorData>) event.getSource(), event.getEventType());
break;
case META_DATA:
listener.onMetaDataChanged((List<MetaData>) event.getSource(), event.getEventType());
break;
default:
throw new IllegalStateException("Unexpected value: " + event.getGroupKey());
}
}
}

该方法内按事件类型分别处理,DataChangedEventDispatcher 同时实现了 InitializingBean 接口,在初始化后完成 listeners 的注入。

五、响应数据变更事件

上面的事件监听处理用到 soul 的 DataChangedListener 接口

DataChangedListener 实现了不同类型事件的事件响应方法用于响应 DataChangedEvent 事件。

1)AbstractDataChangedListener 的 onSelectorChanged 实现:

public void onSelectorChanged(final List<SelectorData> changed, final DataEventTypeEnum eventType) {
if (CollectionUtils.isEmpty(changed)) {
return;
}
// 更新 selector 缓存
this.updateSelectorCache();
// selector 变更后处理,实现具体的变更通知
this.afterSelectorChanged(changed, eventType);
}

可以看到 selector 变更处理是先更缓存后发通知。

2)AbstractDataChangedListener 的 updateSelectorCache 实现:

protected void updateSelectorCache() {
this.updateCache(ConfigGroupEnum.SELECTOR, selectorService.listAll());
}

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

可以看到最终是创建对应的 ConfigDataCache 存入 CACHE。

总结

本篇梳理了 soul-admin 在真正发出数据变更通知前的处理脉络,其策略是:先写库后更缓存,最后发出数据变更通知。

先写库保证数据不丢,另外在集群部署时,其他 soul-admin 节点也可通过浏览页面时查库保证数据一致。

意外学到 spring 的事件通知机制,soul 中的设计果真小巧精妙。

下篇,将探究 http 同步策略的变更通知机制,期待惊喜。

个人知识库

高性能微服务API网关-Soul

【Soul网关探秘】http数据同步-Admin通知前处理的更多相关文章

  1. 【Soul网关探秘】http数据同步-Web端处理变更通知

    个人知识库 引言 上一篇,梳理http 数据同步策略的变更通知机制,本篇开始探究配置变更通知到达后, soul-web 端的处理响应. 不同数据变更的通知机制应当是一致的,故本篇以 selector ...

  2. Soul 网关 Nacos 数据同步源码解析

    学习目标: 学习Soul 网关 Nacos 数据同步源码解析 学习内容: 环境配置 Soul 网关 Nacos 数据同步基本概念 源码分析 学习时间:2020年1月28号 早7点 学习产出: 环境配置 ...

  3. 搞懂 ZooKeeper 集群的数据同步

    本文作者:HelloGitHub-老荀 Hi,这里是 HelloGitHub 推出的 HelloZooKeeper 系列,免费开源.有趣.入门级的 ZooKeeper 教程,面向有编程基础的新手. 项 ...

  4. rsync+inotify实现服务器数据同步

    一.什么是rsync rsync,remote synchronize是一款实现远程同步功能的软件,它在同步文件的同时,可以保持原来文件的权限.时间.软硬链接等附加信息.rsync是用 “rsync算 ...

  5. phpwind将服务器数据同步到本地之后网站不显示或者排版错误

    在将phpwind的数据同步到本地服务器之后 如果访问本地服务器的首页不能显示的话 首先要查看global.php文件中的D_P变量,官方默认 的此变量应该指向和R_P变量是同一个文件夹即网站的根目录 ...

  6. 使用文件监控对象FileSystemWatcher实现数据同步

    最近在项目中有这么个需求,就是得去实时获取某个在无规律改变的文本文件中的内容.首先想到的是用程序定期去访问这个文件,因为对实时性要求很高,间隔不能超过1S,而且每次获取到文本内容都要去分发给WEB服务 ...

  7. oracle数据同步方案

    数据同步方案:--用DBLINK 创建与所需同步表的链接------------------------------------------------------------------------ ...

  8. rsync与inotify 数据同步

    发布:thebaby   来源:脚本学堂     [大 中 小] 本文介绍下,在linux系统中,使用rsync与inotify实现数据同步的一个实例,有研究文件同步的朋友可以作个参考.本文转自:ht ...

  9. C#使用文件监控对象FileSystemWatcher 实现数据同步

    在C#使用文件监控对象FileSystemWatcher 实现数据同步 2013-12-12 18:24 by 幕三少, 352 阅读, 3 评论, 收藏, 编辑 最近在项目中有这么个需求,就是得去实 ...

随机推荐

  1. JQuery特点:

    轻量级 强大的选择器 出色的DOM封装 可靠的事件处理机制 完善的Ajax 出色的浏览器兼容性 丰富的插件支持 完善的文档 支持链式操作

  2. 通过python的socket库实现简易即时通讯小程序

    前言 最近学习了一下有关tcp协议和socket有关的知识,看到许多socket实战都喜欢教如何做一个聊天程序,于是想着试试能不能不看教程自己写一个.当然我没太多时间做一个像qq一样的ui界面,所以做 ...

  3. TurtleBot3 Waffle (tx2版华夫)(5)激活你的雷达

    重要提示:请在配网通信成功后进行操作,配网后再次开机需要重新验证通信: 重要提示:[Remote PC]代表PC端.[TurtelBot]代表树莓派端: 5.1.操作步骤 1)[Remote PC]  ...

  4. Kafka基本原理概述

    Kafka的基本介绍 Kafka是最初由Linkedin公司开发,是一个分布式.分区的.多副本的.多订阅者,基于zookeeper协调的分布式日志系统(也可以当做MQ系统),常见可以用于web/ngi ...

  5. [ABP教程]第五章 授权

    原文档 地址: Web Application Development Tutorial - Part 5: Authorization 关于此教程 在这个教程系列中,您将构建一个基于ABP的Web应 ...

  6. Nexus3.X在linux系统搭建maven私服

    准备工作: 1.linux服务器上需安装jdk(非yum下来的open_jdk!!!,版本1.8以上) 2.linux服务器上需安装maven(如不会,请点击链接,maven版本自己喜欢就好) 准备工 ...

  7. 腾讯IOT之树莓派物联网设备

    目录 腾讯IOT之树莓派物联网设备 硬件配置 软件配置 Tecent IOT 开发平台的使用 新建项目 新建产品 添加自定义功能 设备开发 微信小程序配置 面板配置 新建设备 使用设备 在线调试 设备 ...

  8. mmal商城商品模块总结

    学习目标 FTP服务器的对接 SpringMVC文件上传 流读取properties配置文件 抽象POJO.BO.VO对象之间的转换关系及解决思路 joda-time快速入门 静态代码块 mybati ...

  9. 拍摄、剪辑vlog的思路

    这篇文章是看了很多狂阿弥_ 的作品后 产生的一些小小总结.这些技法只是锦上添花,阿弥作品真正好的地方在于他细腻的情感,真实的对白,和打动人心的满分作文. 优秀的Vlog ,在于它和观众产生的情感共鸣. ...

  10. 【Docker】Docker启动停止重启 Redirecting to /bin/systemctl start docker.service

    [root@liuawen local]# docker -v Docker version 1.13.1, build cccb291/1.13.1 [root@liuawen local]# 启动 ...