Guava EventBus

我稱其為單塊架構(gòu)的利器

前言

在設(shè)計(jì)模式中敏晤, 有一種叫做發(fā)布/訂閱模式茂洒, 即某事件被發(fā)布, 訂閱該事件的角色將自動(dòng)更新采缚。
那么訂閱者和發(fā)布者直接耦合针炉, 也就是說在發(fā)布者內(nèi)要通知訂閱者說我這邊有東西發(fā)布了, 你收一下扳抽。

正如在rxJava中篡帕, 主要就是發(fā)布訂閱設(shè)計(jì)模式

Observable.just(1).subscribe(new Subsriber(){

    @Override
    public void onCompleted() {
    System.out.println("onCompleted ");
    }

    @Override
    public void onError(Throwable arg0) {
    }

    @Override
    public void onNext(Long arg0) {
        System.out.println("onNext " + arg0);
    }
})

我們可以看到, 發(fā)布者發(fā)布一個(gè)數(shù)字1摔蓝, 訂閱者訂閱了這個(gè)

而加入eventBus赂苗, 發(fā)布者與生產(chǎn)者之間的耦合性就降低了。因?yàn)檫@時(shí)候我們?nèi)ス芾韊ventbus就可以贮尉, 發(fā)布者只要向eventbus發(fā)送信息就可以拌滋, 而不需要關(guān)心有多少訂閱者訂閱了此消息。模型如下:


aa64034f78f0f736e9d6d1800355b319ebc41302.jpg

為什么說eventBus 是單塊架構(gòu)的利器呢猜谚?

首先單塊架構(gòu)就是在一個(gè)進(jìn)程內(nèi)败砂, 在一個(gè)進(jìn)程內(nèi), 我們還是希望模塊與模塊之間(功能與功能之間)是松耦合的魏铅,而在一個(gè)模塊中是高度內(nèi)聚的昌犹, 如何降低一定的耦合, 使得代碼更加有結(jié)構(gòu)览芳, guava eventbus就是支持進(jìn)程內(nèi)通訊的橋梁斜姥。

想象一下以下業(yè)務(wù)

我們希望在數(shù)據(jù)到來之后, 進(jìn)行入庫沧竟, 同時(shí)能夠?qū)?shù)據(jù)進(jìn)行報(bào)警預(yù)測(cè)铸敏, 當(dāng)發(fā)生報(bào)警了, 能夠有以下幾個(gè)動(dòng)作悟泵, 向手機(jī)端發(fā)送推送杈笔, 向web端發(fā)送推送, 向手機(jī)端發(fā)送短信糕非。

在一般情況下我們可以這樣實(shí)現(xiàn): (偽代碼如下)

processData(data){
    insertintoDB(data); //執(zhí)行入庫操作
    predictWarning(data);   // 執(zhí)行報(bào)警預(yù)測(cè)
}
在predictWarning(data)中{
    if(data reaches warning line){
        sendNotification2App(data); //向手機(jī)端發(fā)送推送
        sendNotification2Web(data); // 向web端發(fā)送推送
        sendSMS2APP(data);      //手機(jī)端發(fā)送短信
    }
}
在這里我不去講具體是如何向web端發(fā)送推送蒙具, 如何發(fā)送短信球榆。主要用到第三方平臺(tái)

分析

入庫和報(bào)警預(yù)測(cè)是沒有直接聯(lián)系,或者是不分先后順序的禁筏, 同樣在報(bào)警模塊中持钉, 向3個(gè)客戶端發(fā)送信息也應(yīng)該是沒有聯(lián)系的, 所以以上雖然可以實(shí)現(xiàn)功能融师, 但不符合代碼的合理性右钾。

應(yīng)該是怎么樣的邏輯呢? 如下圖


image

當(dāng)數(shù)據(jù)事件觸發(fā)旱爆, 發(fā)布到data EventBus 上舀射, 入庫和預(yù)警分別訂閱這個(gè)eventBus, 就會(huì)觸發(fā)這兩個(gè)事件, 而在預(yù)警事件中怀伦, 將事件發(fā)送到warning EventBus 中脆烟, 由下列3個(gè)訂閱的客戶端進(jìn)行發(fā)送消息。

如何實(shí)現(xiàn)

先來講同步房待, 即訂閱者收到事件后依次執(zhí)行, 下面都是偽代碼邢羔, 具體的入庫細(xì)節(jié)等我在這里不提供。

@Component
public class DataHandler{
    
    @Subscribe
    public void handleDataPersisist(Data data){
        daoImpl.insertData2Mysql(data);
    }
    
    @Subscribe
    public void predictWarning(Data data){
        if(data is warning){ // pseudo code  如果預(yù)警
            Warning warning = createWarningEvent(data);  // 根據(jù)data創(chuàng)建一個(gè)Warning事件
            postWarningEvent(warning)
        }
    }
    
    protected postWarningEvent(Warning warning){
        EventBusManager.warningEventBus.post(warning);// 發(fā)布到warning event 上
    }
    
    @PostConstruct   // 由spring 在初始化bean后執(zhí)行
    public void init(){
        register2DataEventBus();
    }
    
    // 將自己注冊(cè)到eventBus中
    protected void register2DataEventBus(){
        EventBusManager.dataEventBus.register(this);
    }
    
}

@Component
public class WarningHandler{
    @Subscribe
    public void sendNotification2AppClient(Warning warning){
        JpushUtils.sendNotification(warning);
    }
    @Subscribe
    public void sendSMS(Warning warning){
        SMSUtils.sendSMS(warning);
    }
    @Subscribe
    public void send2WebUsingWebSocket(Warning warning){
        WebsocketUtils.sendWarning(warning);
    }
    
    @PostConstruct   // 由spring 在初始化bean后執(zhí)行
    public void init(){
        register2WarningEventBus();
    }
    
    // 將自己注冊(cè)到eventBus中
    protected void register2DataEventBus(){
        EventBusManager.warningEventBus.register(this);
    }
}


/**
 * 管理所有的eventBus
 **/
public class EventBusManager{
    public final static EventBus dataEventBus = new EventBus();
    public final static EventBus warningEventBus = new EventBus();
    
}



簡(jiǎn)化
// 我們發(fā)現(xiàn)每一個(gè)Handler都要進(jìn)行注冊(cè)桑孩,
public abstract class BaseEventBusHandler{
    
    @PostConstruct
    public void init(){
        register2EventBus();
    }
    private void register2EventBus(){
        getEventBus().register(this);
    }
    protected abstract EventBus getEventBus();
}
這樣在寫自己的eventBus只需要

@Component
public class MyEventBus extends BaseEventBusHandler{
    @Override
    protected abstract EventBus getEventBus(){
        retrun EventBusManager.myEventBus;
    }
}

在目前的應(yīng)用場(chǎng)景下拜鹤, 同步是我們不希望的, 異步場(chǎng)景也很容易實(shí)現(xiàn)流椒。
只需要將EventBus 改成
 AsyncEventBus warningEvent = new AsyncEventBus(Executors.newFixedThreadPool(1))
 AsyncEventBus dataEventBus = new AsyncEventBus(Executors.newFixedThreadPool(3))

當(dāng)然還有很多很多場(chǎng)景我們利用發(fā)布和訂閱模式敏簿, 在一定時(shí)候巧妙結(jié)合guavaEventBus, 這樣我們單塊架構(gòu)的結(jié)構(gòu)更加合理。

至于分布式的架構(gòu)宣虾, 我們可以使用MQ 如rabbitMq, kafka惯裕。 這里的篇章我會(huì)在后續(xù)給出。

如果大家感興趣的話: 可以多去看看響應(yīng)式編程绣硝, 有很多特性會(huì)吸引著你蜻势。
如果大家想對(duì)發(fā)布和訂閱設(shè)計(jì)模式是如何實(shí)現(xiàn)的, 其實(shí)也簡(jiǎn)單鹉胖, 后續(xù)我會(huì)簡(jiǎn)單實(shí)現(xiàn)這種設(shè)計(jì)模式握玛。

在本篇最后, 還推薦大家去學(xué)習(xí)一下vert.x 甫菠, 后續(xù)我也會(huì)去補(bǔ)充败许。
在vert.x 中, 用到了eventbus(非guava eventBus)淑蔚。


圖片引用:
圖一: 來自百度百科

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市愕撰,隨后出現(xiàn)的幾起案子刹衫,更是在濱河造成了極大的恐慌醋寝,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,884評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件带迟,死亡現(xiàn)場(chǎng)離奇詭異音羞,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)仓犬,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,755評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門嗅绰,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人搀继,你說我怎么就攤上這事窘面。” “怎么了叽躯?”我有些...
    開封第一講書人閱讀 158,369評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵财边,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我点骑,道長(zhǎng)酣难,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,799評(píng)論 1 285
  • 正文 為了忘掉前任黑滴,我火速辦了婚禮憨募,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘袁辈。我一直安慰自己菜谣,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,910評(píng)論 6 386
  • 文/花漫 我一把揭開白布吵瞻。 她就那樣靜靜地躺著葛菇,像睡著了一般。 火紅的嫁衣襯著肌膚如雪橡羞。 梳的紋絲不亂的頭發(fā)上眯停,一...
    開封第一講書人閱讀 50,096評(píng)論 1 291
  • 那天,我揣著相機(jī)與錄音卿泽,去河邊找鬼莺债。 笑死,一個(gè)胖子當(dāng)著我的面吹牛签夭,可吹牛的內(nèi)容都是我干的齐邦。 我是一名探鬼主播,決...
    沈念sama閱讀 39,159評(píng)論 3 411
  • 文/蒼蘭香墨 我猛地睜開眼第租,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼措拇!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起慎宾,我...
    開封第一講書人閱讀 37,917評(píng)論 0 268
  • 序言:老撾萬榮一對(duì)情侶失蹤丐吓,失蹤者是張志新(化名)和其女友劉穎浅悉,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體券犁,經(jīng)...
    沈念sama閱讀 44,360評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡术健,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,673評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了粘衬。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片荞估。...
    茶點(diǎn)故事閱讀 38,814評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖稚新,靈堂內(nèi)的尸體忽然破棺而出勘伺,到底是詐尸還是另有隱情,我是刑警寧澤枷莉,帶...
    沈念sama閱讀 34,509評(píng)論 4 334
  • 正文 年R本政府宣布娇昙,位于F島的核電站,受9級(jí)特大地震影響笤妙,放射性物質(zhì)發(fā)生泄漏冒掌。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,156評(píng)論 3 317
  • 文/蒙蒙 一蹲盘、第九天 我趴在偏房一處隱蔽的房頂上張望股毫。 院中可真熱鬧,春花似錦召衔、人聲如沸铃诬。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,882評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽趣席。三九已至,卻和暖如春醇蝴,著一層夾襖步出監(jiān)牢的瞬間宣肚,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,123評(píng)論 1 267
  • 我被黑心中介騙來泰國(guó)打工悠栓, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留霉涨,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,641評(píng)論 2 362
  • 正文 我出身青樓惭适,卻偏偏與公主長(zhǎng)得像笙瑟,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子癞志,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,728評(píng)論 2 351

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

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 171,871評(píng)論 25 707
  • 博文出處:EventBus源碼解析往枷,歡迎大家關(guān)注我的博客,謝謝! 0001B 時(shí)近年末错洁,但是也沒閑著茅信。最近正好在看...
    俞其榮閱讀 1,299評(píng)論 1 16
  • 題目描述:安全人員在應(yīng)用市場(chǎng)發(fā)現(xiàn)一個(gè)版本信息異常的應(yīng)用,要求試圖找出該異常墓臭。app下載地址:https://pan...
    _String_閱讀 286評(píng)論 0 0
  • 昨日晚間,騰訊方面確認(rèn)了推出該功能的消息妖谴,并稱這一功能將交給自媒體“自行設(shè)計(jì)”窿锉。騰訊在去年就已被傳出在做付費(fèi)閱讀功...
    到處走走停停閱讀 2,432評(píng)論 0 3
  • 身為10元價(jià)位的飲料,Vita Coco的消費(fèi)目標(biāo)是中產(chǎn)階級(jí)膝舅。這個(gè)群體對(duì)品質(zhì)敏感嗡载,但對(duì)價(jià)格不敏感。他們樂于接受新事...
    陳錦輝閱讀 214評(píng)論 0 0