背景
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, 用來處理關鍵節點的日誌表記錄(就算用錯了, 就是少幾條日誌, 還能接受~). 爲了更好的使用, 下一篇會從閱讀關鍵源碼, 瞭解代碼執行邏輯. 今天就這樣, 下次帶你上秋名山~.~