背景
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, 用来处理关键节点的日志表记录(就算用错了, 就是少几条日志, 还能接受~). 为了更好的使用, 下一篇会从阅读关键源码, 了解代码执行逻辑. 今天就这样, 下次带你上秋名山~.~