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);
    }
}

跑起来~

@Test
public void 科一() {

    AwesomeEventBusDriver.register(new AwesomeStudent());
    AwesomeEventBusDriver.publishAnything("通过~");
}

Ok~ 科一过了
现在是科二, 我们不光想知道过没过, 还要知道得了几分

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, 科二满分通过.
还有考科三的同学一起查成绩

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值