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注解 |
发布消息 | 经过事件总线向全部匹配的监听者提供事件 |