[Soul 源码之旅] 1.4 Soul数据同步

1.4.1 数据同步方式

我们知道Soul数据同步可以配置为 Websocket,Http 长轮询,Zookeeper 和 Nacos 这四种方式,我们从更新Selector的接口作为切入点,根据调用链一步步分析各种数据同步方式。

1.4.1 通用处理链路

在决定使用那种方式发送前都会经过一个通用的分配流程,我们从新Selector的接口出发,SelectorController 的 updateSelector 方法会被端调用进行服务更新。这里调用了 SelectorServiceImpl服务进行更新。


image.png

这里先执行数据库操作,将对应的Selector更新,然后将旧的rule删除,然后再逐条插入新的规则,最终调用到了eventPubliser的publishEvent方法,这里使用了SpringBoot的消息发布机制,最终发布了一个DataChangedEvent类型的消息,我们接着看消息消费者 DataChangedEventDispatcher 。


image.png

DataChangedEventDispatcher 实现了 ApplicationListener<DataChangedEvent> 这个接口,它重写了OnApplicationEvent方法,该方法就是接收消息的方法。同时 DataChangedEventDispatcher 也实现了InitializingBean 接口,他会在所有的Bean都准备就绪后触发 afterPropertiesSet 方法。
image.png

我们看它主要就是查询里面所有实现了 DataChangedListener 方法的实现类,其主要实现类有如下几个。其实就是我们接下来要说的几种数据同步方式。


image.png

我们回过头来看一下 OnApplicationEvent 做了什么,我们可以看到,它主要是轮询所有注册了的Listener,然后根据不同的Group Key 调用对应的方法。listener的方法。
image.png

我们看这里的listener是如何注册进ApplicationContext的呢。我们看它被引用的地方 DataSyncConfiguration ,这里根据我们的配置进行对应的加载,我们看一下websocket的流程:但开启soul.sync.websocket.enabled 的时候会进行bean的加载。这里包括三部分,WebsocketDataChangedListener 即我们刚才被调用的listener;WebsocketCollector 这是个WebSocket 的客户端,主要负责收发数据;ServerEndpointExporter 这个是Spring-WebSocket的一个类,他也实现了SmartInitializingSingleton 接口,他会在每个单例bean注册完成后对其进行扫描是否使用了 ServerEndpoint 注解,然后将该类注入到serverContainer中。
image.png

1.4.2 websocket Server 端更新流程

由于我们是更新selector , 所以会调用listener 的 onSelectorChanged 方法,这里最终还是调用了WebsocketCollector 的send 方法。


源码

我们可以看出来,在Spring中使用WebSocket非常简单,我们只需要使用ServerEndpoint 这个注解定义这个是websocket处理类,OnOpen 这个注解类定义在websocket链接建立后生产对应的session然后回调这个服务,这里将session作为静态属性持有,OnMessage 接收消息处理方法,onClose 链接关闭处理方法。


image.png

我们可以看到Souladmin这里会持有所有的WebSocket链接。
image.png

在发送的时候会给所有的客户端进行发送,这里还有对自定义类型的处理。


发送

1.4.2 websocket Client 端

我们再来看看接收端,我们可以看到使用websocket同步数据,BootStrap需要使用以下依赖

        <dependency>
            <groupId>org.dromara</groupId>
            <artifactId>soul-spring-boot-starter-sync-data-websocket</artifactId>
            <version>${project.version}</version>
        </dependency>

我们找到该项目,这是一个标准的springboot-starter,这里定义个一个自动配置类。


image.png

我们来看一下配置类 WebsocketSyncDataConfiguration, 它主要是初始化了两个Bean 一个是 websocketSyncDataService 即为数据同步服务, 一个是 websocketConfig 即websocket的一些配置项。这里会将以soul.sync.websocket 开头的配置注入到这个类中,这里只有一个属性 urls。


image.png

websocketSyncDataService 这里使用到了 ObjectProvider 这个是SpringFactory到一个扩展点,我们知道在一个方法前Autowrite也可以实现注入,但是假如存在多个参数类是以这里到常见到话Autowrite就懵,
  • 如果注入实例为空时,使用ObjectProvider则避免了强依赖导致的依赖对象不存在异常;主要是 getIfAvailable 这个方法。
  • 如果有多个实例,ObjectProvider的方法会根据Bean实现的Ordered接口或@Order注解指定的先后顺序获取一个Bean。从而了提供了一个更加宽松的依赖注入方式。主要通过 orderedStream 方法返回一个根据order注解的一个bean 的 stream。
    @Bean
    public SyncDataService websocketSyncDataService(final ObjectProvider<WebsocketConfig> websocketConfig, final ObjectProvider<PluginDataSubscriber> pluginSubscriber,
                                           final ObjectProvider<List<MetaDataSubscriber>> metaSubscribers, final ObjectProvider<List<AuthDataSubscriber>> authSubscribers) {
        log.info("you use websocket sync soul data.......");
        return new WebsocketSyncDataService(websocketConfig.getIfAvailable(WebsocketConfig::new), pluginSubscriber.getIfAvailable(),
                metaSubscribers.getIfAvailable(Collections::emptyList), authSubscribers.getIfAvailable(Collections::emptyList));
    }

我们根据debug数据看一下主要注入的参数,PluginDataSubscriber 这个主要是各个插件的Handler 主要负责插件内的数据更新。metaDataSubscribers 元数据订阅者,authDataSubscribers 认证数据订阅。


image.png

这里会根据websocket的配置生成一个SoulWebsocketClient 客户端,然后尝试链接服务端。


image.png

这里会触发服务端的OnMessage方法,然后触发SysnAll方法,向客户端发送所有数据。我们看调用栈,这里会包含所有信息同步给客户端。
synAll

这里包括了插件数据,selector 数据和 rule 数据。

    @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;
    }

我们再看看SoulWebsocketClient 做了什么,其主要是在接收到OnMessge的时候调用websocketDataHandler 进行消息处理。


image.png

websocketDataHandler 里面再注册了各种数据的处理器,如图 包括plugin selector rule app_auth meta 这几种数据的更新。


image.png

我们看handle 是一个default方法,主要是调用各个实现类的refresh方法
handle

我们更新selector主要是做以下操作,更新内存数据,然后通知各个插件数据更新。


image.png

1.4.4 总结

在这期的学习过程中,我学到很一些Spring的新特性如 ObjectProvider,还知道了在SpringBoot中如何写一个WebSocket的客户端。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,029评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,238评论 3 388
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,576评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,214评论 1 287
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,324评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,392评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,416评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,196评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,631评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,919评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,090评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,767评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,410评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,090评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,328评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,952评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,979评论 2 351

推荐阅读更多精彩内容