EventBus是一個消息總線,以觀察者模式實現,用於簡化程序的組件、線程通訊,能夠輕易切換線程、開闢線程; 傳統上,Java的進程內事件分發都是經過發佈者和訂閱者之間的顯式註冊實現的。設計EventBus就是爲了取代這種顯示註冊方式,使組件間有了更好的解耦。EventBus不是通用型的發佈-訂閱實現,不適用於進程間通訊java
開始以前,咱們能夠先想一下,什麼東西是發佈-訂閱模型,若是要讓咱們本身設計一個發佈-訂閱模型的框架,要怎麼處理android
舉一個小例子,談一下個人理解框架
有一個存錢罐,長輩向裏面放錢(1毛,5毛,1元,5元,10元,20元,50元,100元), 晚輩從裏面取錢;與現實有點不一樣的是,每一個長輩只能投相同面額的錢,晚輩只能獲取相同面額的錢 假設小紅,小明,小剛三我的是取10元錢的,如今張三放了10元錢, 而後主動把這10元錢給這三我的,無論他們去幹嗎(與現實不一樣的是,張三隻防了10元錢,可是小紅,小明,小剛都拿到了這10元錢)
接本的業務流程以下:異步
設計:源碼分析
post
使用很是簡單, 建立一個 EventBus
實例, 訂閱方,調用 EventBus.register()
方法註冊, 消息發佈方,調用eventBus.post(event);
來發布消息, 則訂閱類中,添加 @subscribe 註解的方法將會接受到這條消息學習
實例以下:ui
/** * 發送的消息 */ @ToString @Getter @Setter public class AuditEvent { /** * 審覈人 */ private String auditUser; /** * 審覈記錄 */ private String record; /** * 審覈結果 */ private AuditEventEnum auditResultEnum; public enum AuditEventEnum { ACCEPT, REJECT, RETRY; } }
訂閱者this
/** * 初審 & 複審的監聽器 * <p/> * Created by yihui on 2017/3/1. */ @Component public class AuditEventListener { private static final Logger logger = LoggerFactory.getLogger(AuditEventListener.class); /** * 註冊事件 */ @PostConstruct public void init() { ActionEventBus.register(this); } /** * 審覈完成後,會發送一條消息 * <p/> * 1. 經過審覈 * 2. 拒絕審覈 * 3. 從新審覈 * <p/> * 根據消息, 作出不一樣的action * * @param args */ @Subscribe public void invoke(AuditEvent args) { if (args.getAuditResultEnum() == AuditEvent.AuditEventEnum.ACCEPT) { System.out.println(1111); logger.info("審覈經過!!!! {}", args.getRecord()); } else if (args.getAuditResultEnum() == AuditEvent.AuditEventEnum.REJECT) { System.out.println(2222); logger.info("審覈拒絕!!!! {}", args.getRecord()); } else { logger.info("從新審覈!!!! {}", args.getRecord()); } } }
EventBus管理工廠google
public class ActionEventBus { private final static EventBus eventBus = new EventBus(); public static void post(Object event) { eventBus.post(event); } public static void register(Object handler) { eventBus.register(handler); } public static void unregister(Object handler) { eventBus.unregister(handler); } }
發佈消息
@Test public void testAudit() { AuditEvent auditEvent = new AuditEvent(); auditEvent.setAuditResultEnum(AuditEvent.AuditEventEnum.ACCEPT); auditEvent.setAuditUser("1hui"); auditEvent.setRecord("test1"); // 發佈一條成功的消息 ActionEventBus.post(auditEvent); auditEvent.setAuditResultEnum(AuditEvent.AuditEventEnum.REJECT); auditEvent.setAuditUser("2hui"); auditEvent.setRecord("test2"); // 發佈一條拒絕的消息 ActionEventBus.post(auditEvent); BuyEvent buyEvent = new BuyEvent(); buyEvent.setBuyerUser("3hui"); buyEvent.setCount(1); buyEvent.setTotalPrice(10000L); buyEvent.setItem("java book"); buyEvent.setBuyEventEnum(BuyEventEnum.PAY); ActionEventBus.post(buyEvent); System.out.println("over"); }
說明,咱們先拿google的 Guava中的 EventBus 來做爲研究對象; 後續會對比下android平臺上使用很是多的
greenrobot/EventBus
從上面的使用能夠簡單的看出EventBus
的設計思路基本上仍是 消息-訂閱的模子,可是設計很是巧妙
從訂閱者角度來看,首先是要註冊,沒什麼好說的,關鍵點就在於接受消息的處理方法上
- 添加一個註解,指定消息接收類型(即參數類型), 就能夠接受這類消息 - 基於上面的方法,一個訂閱者,能夠實現訂閱多個不一樣的消息源
消息發佈方來看,直接調用 EventBus.post()
就算是發佈消息,使用起來超級簡單
其中 EventBus
做爲溝通的橋樑,也就是上面咱們說的‘儲錢罐’, 若是希冀實現異步的消息處理,則直接用AsyncEventBus
便可
從上面的使用來看,極大的簡化了使用的流程,簡直不能更easy
了; 惟一的遺憾是,從上面的描述中,發現使用異步的話,還得改用AsyncEventBus
有點麻煩,若是能直接再 @subscribe
註解中添加個標識,表示是否使用異步消費就完美了
在真正進入源碼分析以前,咱們先作些準備工做,瞭解下基本的術語和背景
即咱們上面的訂閱者,最終接受事件,並執行響應的業務邏輯的主體
在EventBus實例上調用EventBus.register(Object)
方法註冊事件監聽者;須要注意的是請保證事件生產者和監聽者共享相同的EventBus實例
發送事件的主體,經過把事件傳遞給 EventBus.post(Object)
方法。異步分發能夠直接用EventBus的子類AsyncEventBus
。
術語 | 說明 |
---|---|
事件 | 能夠向事件總線發佈的對象 |
訂閱 | 向事件總線註冊監聽者以接受事件的行爲 |
監聽者 | 提供一個處理方法,但願接受和處理事件的對象 |
處理方法 | 監聽者提供的公共方法,事件總線使用該方法向監聽者發送事件;該方法應該用Subscribe註解 |
發佈消息 | 經過事件總線向全部匹配的監聽者提供事件 |