EventBus

Guava提供的EventBus可以实现不同组件之间解耦,可以向EventBus上注册多个handler,然后通过向EventBus post数据匹配响应的handler,触发handler的处理。handler的执行有同步异步两种方式。事实上,EventBus也是实现了fan-out模型的很好工具类。

EventBus使用只需三步:

  • 创建EventBus实例
  • 向EventBus实例注册handler
  • 向EventBus提交数据

EventBus使用起来还是比较简单的,用一个例子就能演示EventBus的所有功能。代码如下:

public class GuavaEventBusTest {
    private EventBus syncEventBus = new EventBus();
    private AsyncEventBus asyncEventBus = new AsyncEventBus(Executors.newCachedThreadPool());

    class SendMessage {
        @Subscribe
        public void send(Message message) throws InterruptedException {
            Thread.sleep(2000);
            System.out.println("send message :" + message.id + ": " + message.content);
        }
    }

    class SendDB {
        @Subscribe
        public void send(Integer event) {
            System.out.println("send to db: " + event);
        }
    }

    class SendDB1 {
        @Subscribe
        public void send(Integer event) {
            System.out.println("send to db1: " + event);
        }
    }


    class Message {
         int id;
         String content;

        public Message(String content, int id) {
            this.content = content;
            this.id = id;
        }
    }

    /**
     * 演示同步的EventBus,在post的时候,自动的类型匹配找对应的Subscriber
     */
    @Test
    public void test1() {
        syncEventBus.register(new SendMessage());
        syncEventBus.register(new SendDB());
        syncEventBus.post("dianping");  //类型自动匹配
        syncEventBus.post(new Message("hello world", 1));
        syncEventBus.post(1);
    }

    /**
     * 演示异步的EventBus,一定要注意这个bus的创建,这个是将消息的生产和处理彻底解耦了
     *
     * @throws InterruptedException
     */
    @Test
    public void test2() throws InterruptedException {
        asyncEventBus.register(new SendMessage());
        asyncEventBus.register(new SendDB());
        asyncEventBus.register(new SendDB1());
        asyncEventBus.post("dianping");  //类型自动匹配
        asyncEventBus.post(new Message("hello world", 1));
        asyncEventBus.post(1);
        Thread.sleep(3000);
    }

    /**
     * 演示在一个类中有多个Subscribe处理方法
     */
    @Test
    public void test3() {
        MutilHandler mutilHandler = new MutilHandler();
        asyncEventBus.register(mutilHandler);
        asyncEventBus.post(1);//每个post都会占用AsyncEventBus的线程池中的一个线程
        asyncEventBus.post(2);
        asyncEventBus.post(new Message("zhangsan", 1));
        asyncEventBus.post(new Message("lisi", 2));
    }

    /**
     * 演示DeadEvent,在没有任何Event匹配上的时候,走DeadEvent
     * 作为使用EventBus的良好习惯,永远将Bus上注册一个DeadEvent,并在其中记录日志(小范围使用可以不这么搞)
     */
    @Test
    public void test4() {
        asyncEventBus.register(new MutilHandler());
        asyncEventBus.register(new DeadEventHandler());
        asyncEventBus.post(new Long(1));//没有任何Subscribe类型匹配上的话,就会调用DeadEvent
    }

    /**
     * 演示类型匹配时,如果实参类型是Subscribe定义的形参类型的子类,依然能够匹配上
     */
    @Test
    public void test5() {
        asyncEventBus.register(new StringHandler());
        asyncEventBus.post(new String("zhangsan"));
        asyncEventBus.post(new StringBuffer("lisi"));
    }

    class MutilHandler {
        @Subscribe
        public void handleInteger(Integer i) {
            System.out.println(Thread.currentThread().getName() + ": handle integer " + i);
        }

        @Subscribe
        public void handlerMessage(GuavaEventBusTest.Message message) {
            System.out.println(Thread.currentThread().getName() + ": handle message " + message.content);
        }
    }

    class DeadEventHandler {
        @Subscribe
        public void handleDeadEvent(DeadEvent event) {
            System.out.println("dead event: " + event.getEvent());
        }
    }

    class StringHandler {

        @Subscribe
        public void handleString(String s) {
            System.out.println("handle string: " + s);
        }

        @Subscribe
        public void handleCharSequence(CharSequence cs) {
            System.out.println("handle CharSequence: " + cs);
        }
    }
}

定义了两种EventBus,同步的和异步的,异步EventBus需要知道handler执行的线程池。

test1演示了同步EventBus,代码syncEventBus.register(new SendMessage());向EventBus注册了处理类。可以看出,成为一个处理类:

  • 类名任意,不需要实现特定接口
  • 类中的方法名任意,参数任意
  • 处理方法需要@Subscribe注解

要求的确很低,只需要@Subscribe注解,其他没啥要求。代码syncEventBus.post("dianping")向EventBus提交了一个数据,post方法只能接受一个Object类型的参数,多个参数封装成对象。只要和post提交的数据类型匹配的方法都会被执行,类型匹配是指:

  • 处理方法参数的个数为1个
  • 处理方法参数的类型和post数据相同或为它的父类

若提交的数据没有匹配任何处理方法的参数,则不会被任何方法处理。在test1中,字符串类型"dianping"就不会被任何方法接收处理。执行结果:

send message :1: hello world
send to db: 1

test2在test1的基础上增加一个SendDB1,并改成异步的EventBus,说明如果post的数据匹配多个处理方法,则每个方法都会收到数据并执行,同时可以看到异步执行的效果。结果如下:

send to db: 1
send to db1: 1
send message :1: hello world

test3在同一个类中定义了多个处理方法,并分别用@Subscribe注解,可以看到每个方法都会被触发执行,执行结果:

pool-1-thread-1: handle integer 1
pool-1-thread-2: handle integer 2
pool-1-thread-2: handle message zhangsan
pool-1-thread-1: handle message lisi

test4定义了一个DeadEventHandler,没有匹配任何处理方法的数据会触发这个方法执行,在方法中可以拿到这个数据,执行结果:

dead event: 1

test5定义了一个StringHandler,演示了参数为提交的数据类型父类,也可以被触发执行,因为CharSequence是StringBuffer的父类,所以post(new StringBuffer("lisi"))也会触发它的执行,结果如下:

handle CharSequence: zhangsan
handle string: zhangsan
handle CharSequence: lisi

results matching ""

    No results matching ""