[Soul 源碼之旅] 1.4 Soul數(shù)據(jù)同步

1.4.1 數(shù)據(jù)同步方式

我們知道Soul數(shù)據(jù)同步可以配置為 Websocket咙鞍,Http 長(zhǎng)輪詢房官,Zookeeper 和 Nacos 這四種方式,我們從更新Selector的接口作為切入點(diǎn)续滋,根據(jù)調(diào)用鏈一步步分析各種數(shù)據(jù)同步方式翰守。

1.4.1 通用處理鏈路

在決定使用那種方式發(fā)送前都會(huì)經(jīng)過(guò)一個(gè)通用的分配流程,我們從新Selector的接口出發(fā)蜡峰,SelectorController 的 updateSelector 方法會(huì)被端調(diào)用進(jìn)行服務(wù)更新湿颅。這里調(diào)用了 SelectorServiceImpl服務(wù)進(jìn)行更新油航。


image.png

這里先執(zhí)行數(shù)據(jù)庫(kù)操作谊囚,將對(duì)應(yīng)的Selector更新镰踏,然后將舊的rule刪除余境,然后再逐條插入新的規(guī)則灌诅,最終調(diào)用到了eventPubliser的publishEvent方法含末,這里使用了SpringBoot的消息發(fā)布機(jī)制佣盒,最終發(fā)布了一個(gè)DataChangedEvent類型的消息,我們接著看消息消費(fèi)者 DataChangedEventDispatcher 叶撒。


image.png

DataChangedEventDispatcher 實(shí)現(xiàn)了 ApplicationListener<DataChangedEvent> 這個(gè)接口,它重寫(xiě)了OnApplicationEvent方法耀石,該方法就是接收消息的方法滞伟。同時(shí) DataChangedEventDispatcher 也實(shí)現(xiàn)了InitializingBean 接口梆奈,他會(huì)在所有的Bean都準(zhǔn)備就緒后觸發(fā) afterPropertiesSet 方法亩钟。
image.png

我們看它主要就是查詢里面所有實(shí)現(xiàn)了 DataChangedListener 方法的實(shí)現(xiàn)類径荔,其主要實(shí)現(xiàn)類有如下幾個(gè)总处。其實(shí)就是我們接下來(lái)要說(shuō)的幾種數(shù)據(jù)同步方式鹦马。


image.png

我們回過(guò)頭來(lái)看一下 OnApplicationEvent 做了什么荸频,我們可以看到旭从,它主要是輪詢所有注冊(cè)了的Listener和悦,然后根據(jù)不同的Group Key 調(diào)用對(duì)應(yīng)的方法鸽素。listener的方法馍忽。
image.png

我們看這里的listener是如何注冊(cè)進(jìn)ApplicationContext的呢遭笋。我們看它被引用的地方 DataSyncConfiguration 瓦呼,這里根據(jù)我們的配置進(jìn)行對(duì)應(yīng)的加載,我們看一下websocket的流程:但開(kāi)啟soul.sync.websocket.enabled 的時(shí)候會(huì)進(jìn)行bean的加載谎替。這里包括三部分钱贯,WebsocketDataChangedListener 即我們剛才被調(diào)用的listener秩命;WebsocketCollector 這是個(gè)WebSocket 的客戶端弃锐,主要負(fù)責(zé)收發(fā)數(shù)據(jù)霹菊;ServerEndpointExporter 這個(gè)是Spring-WebSocket的一個(gè)類旋廷,他也實(shí)現(xiàn)了SmartInitializingSingleton 接口饶碘,他會(huì)在每個(gè)單例bean注冊(cè)完成后對(duì)其進(jìn)行掃描是否使用了 ServerEndpoint 注解扎运,然后將該類注入到serverContainer中豪治。
image.png

1.4.2 websocket Server 端更新流程

由于我們是更新selector 鬼吵, 所以會(huì)調(diào)用listener 的 onSelectorChanged 方法篮赢,這里最終還是調(diào)用了WebsocketCollector 的send 方法启泣。


源碼

我們可以看出來(lái)寥茫,在Spring中使用WebSocket非常簡(jiǎn)單纱耻,我們只需要使用ServerEndpoint 這個(gè)注解定義這個(gè)是websocket處理類弄喘,OnOpen 這個(gè)注解類定義在websocket鏈接建立后生產(chǎn)對(duì)應(yīng)的session然后回調(diào)這個(gè)服務(wù),這里將session作為靜態(tài)屬性持有累奈,OnMessage 接收消息處理方法澎媒,onClose 鏈接關(guān)閉處理方法戒努。


image.png

我們可以看到Souladmin這里會(huì)持有所有的WebSocket鏈接柏卤。
image.png

在發(fā)送的時(shí)候會(huì)給所有的客戶端進(jìn)行發(fā)送缘缚,這里還有對(duì)自定義類型的處理桥滨。


發(fā)送

1.4.2 websocket Client 端

我們?cè)賮?lái)看看接收端,我們可以看到使用websocket同步數(shù)據(jù)纷跛,BootStrap需要使用以下依賴

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

我們找到該項(xiàng)目贫奠,這是一個(gè)標(biāo)準(zhǔn)的springboot-starter,這里定義個(gè)一個(gè)自動(dòng)配置類拷恨。


image.png

我們來(lái)看一下配置類 WebsocketSyncDataConfiguration小泉, 它主要是初始化了兩個(gè)Bean 一個(gè)是 websocketSyncDataService 即為數(shù)據(jù)同步服務(wù)冕杠, 一個(gè)是 websocketConfig 即websocket的一些配置項(xiàng)分预。這里會(huì)將以soul.sync.websocket 開(kāi)頭的配置注入到這個(gè)類中噪舀,這里只有一個(gè)屬性 urls。


image.png

websocketSyncDataService 這里使用到了 ObjectProvider 這個(gè)是SpringFactory到一個(gè)擴(kuò)展點(diǎn),我們知道在一個(gè)方法前Autowrite也可以實(shí)現(xiàn)注入纺座,但是假如存在多個(gè)參數(shù)類是以這里到常見(jiàn)到話Autowrite就懵,
  • 如果注入實(shí)例為空時(shí)少欺,使用ObjectProvider則避免了強(qiáng)依賴導(dǎo)致的依賴對(duì)象不存在異常馋贤;主要是 getIfAvailable 這個(gè)方法配乓。
  • 如果有多個(gè)實(shí)例,ObjectProvider的方法會(huì)根據(jù)Bean實(shí)現(xiàn)的Ordered接口或@Order注解指定的先后順序獲取一個(gè)Bean崎页。從而了提供了一個(gè)更加寬松的依賴注入方式飒焦。主要通過(guò) orderedStream 方法返回一個(gè)根據(jù)order注解的一個(gè)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));
    }

我們根據(jù)debug數(shù)據(jù)看一下主要注入的參數(shù),PluginDataSubscriber 這個(gè)主要是各個(gè)插件的Handler 主要負(fù)責(zé)插件內(nèi)的數(shù)據(jù)更新。metaDataSubscribers 元數(shù)據(jù)訂閱者挑辆,authDataSubscribers 認(rèn)證數(shù)據(jù)訂閱鱼蝉。


image.png

這里會(huì)根據(jù)websocket的配置生成一個(gè)SoulWebsocketClient 客戶端箫荡,然后嘗試鏈接服務(wù)端羔挡。


image.png

這里會(huì)觸發(fā)服務(wù)端的OnMessage方法绞灼,然后觸發(fā)SysnAll方法,向客戶端發(fā)送所有數(shù)據(jù)印叁。我們看調(diào)用棧轮蜕,這里會(huì)包含所有信息同步給客戶端跃洛。
synAll

這里包括了插件數(shù)據(jù)税课,selector 數(shù)據(jù)和 rule 數(shù)據(jù)韩玩。

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

我們?cè)倏纯碨oulWebsocketClient 做了什么陆馁,其主要是在接收到OnMessge的時(shí)候調(diào)用websocketDataHandler 進(jìn)行消息處理叮贩。


image.png

websocketDataHandler 里面再注冊(cè)了各種數(shù)據(jù)的處理器,如圖 包括plugin selector rule app_auth meta 這幾種數(shù)據(jù)的更新寸莫。


image.png

我們看handle 是一個(gè)default方法膘茎,主要是調(diào)用各個(gè)實(shí)現(xiàn)類的refresh方法
handle

我們更新selector主要是做以下操作,更新內(nèi)存數(shù)據(jù)盐数,然后通知各個(gè)插件數(shù)據(jù)更新。


image.png

1.4.4 總結(jié)

在這期的學(xué)習(xí)過(guò)程中,我學(xué)到很一些Spring的新特性如 ObjectProvider漾峡,還知道了在SpringBoot中如何寫(xiě)一個(gè)WebSocket的客戶端灰殴。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市伟阔,隨后出現(xiàn)的幾起案子皱炉,更是在濱河造成了極大的恐慌狮鸭,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,430評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異赌髓,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)夷野,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,406評(píng)論 3 398
  • 文/潘曉璐 我一進(jìn)店門(mén)悯搔,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)妒貌,“玉大人苏揣,你說(shuō)我怎么就攤上這事推姻〔毓牛” “怎么了忍燥?”我有些...
    開(kāi)封第一講書(shū)人閱讀 167,834評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵厂捞,是天一觀的道長(zhǎng)靡馁。 經(jīng)常有香客問(wèn)我机久,道長(zhǎng)膘盖,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,543評(píng)論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮软棺,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘德崭。我一直安慰自己眉厨,他們只是感情好憾股,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,547評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布服球。 她就那樣靜靜地躺著斩熊,像睡著了一般粉渠。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上雕沉,一...
    開(kāi)封第一講書(shū)人閱讀 52,196評(píng)論 1 308
  • 那天坡椒,我揣著相機(jī)與錄音尤溜,去河邊找鬼缀雳。 笑死肥印,一個(gè)胖子當(dāng)著我的面吹牛深碱,可吹牛的內(nèi)容都是我干的敷硅。 我是一名探鬼主播功咒,決...
    沈念sama閱讀 40,776評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼绞蹦!你這毒婦竟也來(lái)了力奋?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,671評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤幽七,失蹤者是張志新(化名)和其女友劉穎景殷,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體澡屡,經(jīng)...
    沈念sama閱讀 46,221評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡猿挚,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,303評(píng)論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了驶鹉。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,444評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡词顾,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出上忍,到底是詐尸還是另有隱情,我是刑警寧澤吓笙,帶...
    沈念sama閱讀 36,134評(píng)論 5 350
  • 正文 年R本政府宣布尊搬,位于F島的核電站幌墓,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜您没,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,810評(píng)論 3 333
  • 文/蒙蒙 一仆抵、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦趣竣、人聲如沸宵呛。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,285評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)堪藐。三九已至杉辙,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間岖食,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,399評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工存和, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留芜茵,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,837評(píng)論 3 376
  • 正文 我出身青樓胆建,卻偏偏與公主長(zhǎng)得像涯呻,于是被迫代替她去往敵國(guó)和親雄家。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,455評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容

  • 單頁(yè)應(yīng)用的一個(gè)特點(diǎn)就是即時(shí)響應(yīng),對(duì)發(fā)生變化數(shù)據(jù)實(shí)現(xiàn) UI 的快速變更层宫。實(shí)現(xiàn)的基礎(chǔ)技術(shù)不外乎 AJAX 和 WebS...
    竇豆逗閱讀 941評(píng)論 0 0
  • 目標(biāo) soul 目錄結(jié)構(gòu)介紹 soul-admin 與 soul-bootstrap數(shù)據(jù)同步之websockets...
    nuopromise閱讀 804評(píng)論 0 1
  • 需求:websocket接收的數(shù)據(jù)要同步更新到子組件中 問(wèn)題:websocket接收方法寫(xiě)在父組件峦筒,message...
    請(qǐng)叫我sophie_閱讀 857評(píng)論 0 0
  • 久違的晴天,家長(zhǎng)會(huì)。 家長(zhǎng)大會(huì)開(kāi)好到教室時(shí),離放學(xué)已經(jīng)沒(méi)多少時(shí)間了实幕。班主任說(shuō)已經(jīng)安排了三個(gè)家長(zhǎng)分享經(jīng)驗(yàn)。 放學(xué)鈴聲...
    飄雪兒5閱讀 7,524評(píng)論 16 22
  • 今天感恩節(jié)哎府蛇,感謝一直在我身邊的親朋好友。感恩相遇!感恩不離不棄。 中午開(kāi)了第一次的黨會(huì)妆棒,身份的轉(zhuǎn)變要...
    迷月閃星情閱讀 10,567評(píng)論 0 11