guava EventBus 學習一

背景

event bus 數據總線, 數據發送者發送信息到總線, 數據接收者從總線接收數據. 大概相似於下飛機去取行李的時候, 旅客在行李傳送帶旁邊等候本身的行李, 在這個場景下, 飛機至關於發送者, 旅客爲接收者, 傳送帶就是咱們的數據總線, 旅客上飛機就是一個註冊的過程. 與咱們後面準備學習的guava中的EventBus不一樣的是, 旅客是本身"拉取"的行李, 可是在guava中是總線根據註冊信息推送消息到訂閱者. 更恰當的例子是去餐廳吃飯, 顧客進入餐廳並坐下, 這就是註冊. 顧客點餐這就是訂閱. 廚師作出來的菜會根據點餐列表, 將菜送到顧客面前, 這就是消息的發送, 若是多個顧客點了同一道菜, 那麼廚師會作多道菜(? 多個副本?), 並分別送到對應的顧客面前. 給個人感受就像一個系統內部的一個MQ~ 廢話到此結束, 下面經過demo瞭解下如何使用guava中的EventBus數據庫

EventBus

環境

guava版本網絡

<dependency>
    <artifactId>guava</artifactId>
    <groupId>com.google.guava</groupId>
    <version>28.0-jre</version>
</dependency>

jdk1.8 Junit4併發

<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.12</version>
    <scope>test</scope>
</dependency>

駕照

guava的EventBus使用上突出一個簡單, 咱們只須要在EventBus上註冊監聽, 而後往EventBus發送消息, 最後根據消息類型將消息發給監聽者. 代碼代碼~搞起搞起~異步

// 創建一個數據工具類, 你是司機, 往哪開你說了算~
public class AwesomeEventBusDriver {

    // 準備好車
    private static EventBus eventBus = new EventBus();

    // 上車
    public static void register(Object object) {
        eventBus.register(object);
    }
    // 發車
    public static void publishAnything(Object object) {
        eventBus.post(object);
    }
}
// 學員
public class AwesomeStudent {

    // 發車了要告訴我
    @Subscribe
    public void listen(String obj) {

        System.out.println("科一" + obj);
    }
}

跑起來~async

@Test
public void 科一() {

    AwesomeEventBusDriver.register(new AwesomeStudent());
    AwesomeEventBusDriver.publishAnything("經過~");
}

Ok~ 科一過了 如今是科二, 咱們不光想知道過沒過, 還要知道得了幾分ide

public class AwesomeStudent_1 {

    @Subscribe
    public void 科二(String obj) {

        System.out.println("科二" + obj);
    }

    @Subscribe
    public void 科二分數(Integer obj) {

        System.out.println("科二分數" + obj);
    }
}

考科二拉工具

@Test
public void 科二() {

    AwesomeEventBusDriver.register(new AwesomeStudent_1());
    AwesomeEventBusDriver.publishAnything("經過~");
    AwesomeEventBusDriver.publishAnything(100);
}

能夠看到不一樣的數據類型會進入不一樣的方法執行. ok, 科二滿分經過. 還有考科三的同窗一塊兒查成績post

public class AwesomeStudent_2 {

    @Subscribe
    public void 科三分數(Double obj) {

        System.out.println("科三" + obj);
    }
}
@Test
public void 科三() {

    AwesomeEventBusDriver.register(new AwesomeStudent_1());
    AwesomeEventBusDriver.register(new AwesomeStudent_2());
    AwesomeEventBusDriver.publishAnything(100);
    AwesomeEventBusDriver.publishAnything(90.5);
}

多個類和多個方法區別不大. 最後科四~學習

// 教練來嘍
public class AwesomeCoach {

    @Subscribe
    public void all(DeadEvent event) {

        System.out.println(event);
    }
}
// 自定義了兩個類
public class AwesomeMessageEvent {

    private String message;

    public AwesomeMessageEvent(String message){
        this.message = message;
    }

    @Override
    public String toString() {
        return "AwesomeEvent{" +
                "message='" + message + '\'' +
                '}';
    }
}

public class AwesomeMoneyEvent {

    private String message;

    public AwesomeMoneyEvent(String message){
        this.message = message;
    }

    @Override
    public String toString() {
        return "AwesomeMoneyEvent{" +
                "message='" + message + '\'' +
                '}';
    }
}
@Test
public void 科四() {

    AwesomeEventBusDriver.register(new AwesomeStudent_1());
    AwesomeEventBusDriver.register(new AwesomeStudent_2());
    AwesomeEventBusDriver.register(new AwesomeCoach());
    AwesomeEventBusDriver.publishAnything(100);
    AwesomeEventBusDriver.publishAnything(90.5);
    AwesomeEventBusDriver.publishAnything(new AwesomeMessageEvent("教練通融下"));
    AwesomeEventBusDriver.publishAnything(new AwesomeMoneyEvent("教練這是點小意思~"));
}

運行後會發現coach會接收到測試中最後兩個自定義的消息類, 這就是DeadEvent的做用, 它的意思就是接收沒有訂閱者訂閱的消息.測試

好了, 駕照拿到, 咱們來總結下 1 消息總線EventBus有點像MQ. 2 EventBus使用很是簡單, 咱們只須要提供三部分: EventBus類, 訂閱者(@Subscribe註解方法), 消息類(若是須要監聽的話). 而後經過EventBus註冊訂閱者, 併發送消息給訂閱者. 3 消息路由依據消息類型, 若是有多個訂閱者就會發送多份消息. 若是發送的消息沒有對應的訂閱者, 則該消息會包含在DeadEvent中, 咱們訂閱該類消息, 專門處理沒有人處理的消息. 若是有訂閱者訂閱的是Object類消息, 也就不會存在DeadEvent消息了.

上路

拿到駕照立刻上路搞起~

public class AwesomeAsyncSubscriber {

    // 我要上內存的車
    @Subscribe
    public void cpu(Integer money) {

        System.out.println("cpu :" + money);
    }

    // 我要上筆記本的車
    @Subscribe
    public void laptop(Long money) throws InterruptedException {

        int count = 3;
        while (count > 0) {
            count--;
            Thread.sleep(1000);
        }
        System.out.println("laptop :" + money);
    }

    // 我要上不能說的車
    @Subscribe
    public void poxn(String seed) throws InterruptedException {

        System.out.println("poxn " + seed);
        System.out.println("downloading ...0%");
        int count = 5;
        while (count > 0) {
            count--;
            Thread.sleep(1000);
        }

        System.out.println("99%...100%");
    }
}

開車~

@Test
public void 同步開車() {

    AwesomeEventBusDriver.register(new AwesomeAsyncSubscriber());

    AwesomeEventBusDriver.publishAnything("xxxx");
    AwesomeEventBusDriver.publishAnything(2990);
    AwesomeEventBusDriver.publishAnything(200L);
}

運行後, 敏銳的你確定發現了...種子很差下啊~ 不是網速不行就是資源不行, 下不下來後面的同志就沒辦法接收到消息. 這就是EventBus的同步模式. 咱們應該儘可能避免在同步模式中使用耗時操做, 好比數據庫操做, 網絡請求等, 或者咱們能夠在接收到消息後異步執行耗時操做, 再或者咱們能夠直接異步接收消息. 修改下老司機

public class AwesomeEventBusDriver {

    // 增長異步總線; 開兩個線程
    private static EventBus asyncEventBus = new AsyncEventBus(Executors.newFixedThreadPool(2));

    private static EventBus eventBus = new EventBus();
    // 註冊到異步總線
    public static void registerAsync(Object object) {
        asyncEventBus.register(object);
    }
    // 發送消息到異步總線
    public static void publishAsyncAnything(Object object) {
        asyncEventBus.post(object);
    }

    public static void register(Object object) {
        eventBus.register(object);
    }

    public static void publishAnything(Object object) {
        eventBus.post(object);
    }
}

異步發車

@Test
public void 異步開車() throws InterruptedException {

    AwesomeEventBusDriver.registerAsync(new AwesomeAsyncSubscriber());

    AwesomeEventBusDriver.publishAsyncAnything("xxxx");
    AwesomeEventBusDriver.publishAsyncAnything(200L);
    AwesomeEventBusDriver.publishAsyncAnything(2990);

    int i = 0;
    while (AwesomeAsyncSubscriber.running) {

        Thread.sleep(1000);
        i++;
        System.out.println(i + "s");
    }
}

上路總結 1 訂閱者接收消息的順序是和消息發送的順序一致的(只是表現是這樣的, 下一篇從源碼中一探究竟) 2 同步發送時, 只有當訂閱者處理完消息後纔會發送下一個消息 3 異步發送時, 同時發送消息數量取決於定義EventBus時指定的線程數.

總結

以上經過幾個簡單的例子, 講了下EventBus的簡單使用, 固然學習最好的辦法仍是理論加實踐, 後面會在項目中加入EventBus, 用來處理關鍵節點的日誌表記錄(就算用錯了, 就是少幾條日誌, 還能接受~). 爲了更好的使用, 下一篇會從閱讀關鍵源碼, 瞭解代碼執行邏輯. 今天就這樣, 下次帶你上秋名山~.~

相關文章
相關標籤/搜索