前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >google Guava之EventBus

google Guava之EventBus

作者头像
栋先生
发布2018-09-29 16:52:26
1.3K0
发布2018-09-29 16:52:26
举报
文章被收录于专栏:Java成长之路Java成长之路

EventBus是Guava的事件处理机制,是设计模式中的观察者模式(生产/消费者编程模型)的优雅实现,在应用中可以处理一些异步任务。对于事件监听和发布订阅模式,EventBus是一个非常优雅和简单解决方案,我们不用创建复杂的类和接口层次结构。

EventBus流程图

EventBus实际上是一个消息队列,Event Source发送一个消息到EventBus,然后再由EventBus将消息推送到所监听的Listener。

EventBus基本用法

1. 创建Listener

我们可以通过@Subscribe注解将任意的类的方法变为一个Listener。

代码语言:javascript
复制
public class SimpleListener {
    private final static Logger LOGGER = LoggerFactory.getLogger(SimpleListener.class);

    /**
     * 一个简单的Listener方法
     * @param event Guava规定此处只能有一个参数
     */
    @Subscribe
    public void doAction(final String event){
        if (LOGGER.isInfoEnabled()){
            LOGGER.info("Received event [{}] and will take a action", event);
        }
    }
}

2. 创建EventBus并发送消息

然后我们可以定义一个EventBus,先将上面的这个Listener类进行注册,通过Post方法即可向其发送消息。

代码语言:javascript
复制
public class SimpleEventBusExample {
    public static void main(String[] args) {
        final EventBus eventBus = new EventBus();
        //注册Listener
        eventBus.register(new SimpleListener());
        System.out.println("post the simple event.");
        //向订阅者发送消息
        eventBus.post("Simple Event");
    }
}

Output: post the simple event. 2018-05-20 22:24:12:INFO main com.guava.eventbus.listeners.SimpleListener - Received event [Simple Event] and will take a action

Listener之间的继承关系

本小节我们来测试一下,当两个Listener之间有继承关系时,只注册子类的Listener到EventBus。然后发送向EventBus发送消息,父类Listener是否会接收到消息呢?

首先定义一个抽象类的Listener。

代码语言:javascript
复制
public abstract class AbstractListener {
    private final static Logger LOGGER = LoggerFactory.getLogger(AbstractListener.class);

    @Subscribe
    public void commonTask(final String event){
        if (LOGGER.isInfoEnabled()){
            LOGGER.info("Received event [{}] will be handle by {}.{}", new Object[]{event,this.getClass().getSimpleName(),"commonTask"});
        }
    }
}

然后定义两个实现类BaseListener和ConcreteListener。

代码语言:javascript
复制
public class BaseListener extends AbstractListener{
    private final static Logger LOGGER = LoggerFactory.getLogger(AbstractListener.class);

    @Subscribe
    public void baseTask(final String event){
        if (LOGGER.isInfoEnabled()){
            LOGGER.info("Received event [{}] will be handle by {}.{}", new Object[]{event,this.getClass().getSimpleName(),"baseTask"});
        }
    }
}

public class ConcreteListener extends BaseListener {

    private final static Logger LOGGER = LoggerFactory.getLogger(AbstractListener.class);

    @Subscribe
    public void conTask(final String event){
        if (LOGGER.isInfoEnabled()){
            LOGGER.info("Received event [{}] will be handle by {}.{}", new Object[]{event,this.getClass().getSimpleName(),"conTask"});
        }
    }
}

定义EventBus:

代码语言:javascript
复制
public class InheritListenersEventBusExample {
    public static void main(String[] args) {
        final EventBus eventBus = new EventBus();
        eventBus.register(new ConcreteListener());
        System.out.println("post the string event.");
        eventBus.post("I am String event");
        System.out.println("post the int event.");
        eventBus.post(1000);
    }
}

结论:注册了一个Listener,使用eventBus发送消息它的父类的Subscribe也会对此消息进行处理。

Subscriber

不同类型参数的Subscribe

本小节我们来测试一下,向EventBus发送消息后,当有多个不同类型的Subscribe时,它们是怎么进行通信的呢?

定义Subscribe

代码语言:javascript
复制
public class MultipleEventListeners {
    private final static Logger LOGGER = LoggerFactory.getLogger(MultipleEventListeners.class);

    @Subscribe
    public void task1(final String event){
        if (LOGGER.isInfoEnabled()){
            LOGGER.info("Received event [{}] and will take a action by ==task1==", event);
        }
    }

    @Subscribe
    public void task2(final String event){
        if (LOGGER.isInfoEnabled()){
            LOGGER.info("Received event [{}] and will take a action by ==task2==", event);
        }
    }

    @Subscribe
    public void intTask(final Integer event){
        if (LOGGER.isInfoEnabled()){
            LOGGER.info("Received event [{}] and will take a action by ==intTask==", event);
        }
    }
}

定义EventBus:

代码语言:javascript
复制
public class MultipleEventBusExample {
    public static void main(String[] args) {
        final EventBus eventBus = new EventBus();
        eventBus.register(new MultipleEventListeners());
        System.out.println("post the string event.");
        eventBus.post("I am String event");
        System.out.println("post the int event.");
        eventBus.post(1000);
    }
}

Output: post the string event. 2018-05-20 22:28:23:INFO main com.guava.eventbus.listeners.MultipleEventListeners - Received event [I am String event] and will take a action by ==task1== 2018-05-20 22:28:23:INFO main com.guava.eventbus.listeners.MultipleEventListeners - Received event [I am String event] and will take a action by ==task2== post the int event. 2018-05-20 22:28:23:INFO main com.guava.eventbus.listeners.MultipleEventListeners - Received event [1000] and will take a action by ==intTask==

结论:eventBus会根据Listener的参数类型的不同,分别向不同的Subscribe发送不同的消息。

event

继承关系的event

本小节来测试:当event之间具有继承关系时,listener之间怎么调用?

定义两个具有继承关系的event:

代码语言:javascript
复制
public class Apple extends Fruit {

    public Apple(String name) {
        super(name);
    }
}
public class Fruit {
    private final String name;

    public Fruit(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    @Override public String toString() {
        return "Fruit{" +
            "name='" + name + '\'' +
            '}';
    }
}

定义对应的Listener:

代码语言:javascript
复制
public class FruitEaterListener {
    private final static Logger LOGGER = LoggerFactory.getLogger(FruitEaterListener.class);

    @Subscribe
    public void eat(Fruit event){
        if (LOGGER.isInfoEnabled()){
            LOGGER.info("Fruit eat[{}]. ", event);
        }
    }
    @Subscribe
    public void eat(Apple event){
        if (LOGGER.isInfoEnabled()){
            LOGGER.info("Apple eat[{}]. ", event);
        }
    }
}

定义EventBus:

代码语言:javascript
复制
public class InheritEventsBusExample {
    public static void main(String[] args) {
        final EventBus eventBus = new EventBus();
        eventBus.register(new FruitEaterListener());
        eventBus.post(new Apple("apple"));

        System.out.println("---------------------");
        eventBus.post(new Fruit("Fruit"));
    }
}

Output: 2018-06-03 16:55:32:INFO main com.guava.eventbus.listeners.FruitEaterListener - Apple eat[Fruit{name=’apple’}]. 2018-06-03 16:55:32:INFO main com.guava.eventbus.listeners.FruitEaterListener - Fruit eat[Fruit{name=’apple’}]. 2018-06-03 16:55:32:INFO main com.guava.eventbus.listeners.FruitEaterListener - Fruit eat[Fruit{name=’Fruit’}].

结论:当作为参数的event之间有继承关系时,使用eventBus发送消息,eventt的父类listener也会对此消息进行处理。

DeadEvent

当EventBus发布了一个事件,但是注册的订阅者中没有找到处理该事件的方法,那么EventBus就会把该事件包装成一个DeadEvent事件来重新发布;我们在应用中可以提供如下的事件处理方法来处理DeadEvent。

创建listener:

代码语言:javascript
复制
public class DeadEventListener {
    @Subscribe
    public void handle(DeadEvent event){
        //获取事件源
        System.out.println(event.getSource());//DEAD-EVENT-BUS
        //获取事件
        System.out.println(event.getEvent());//DeadEventListener event
    }
}

创建EventBus:

代码语言:javascript
复制
public class DeadEventBusExample {
    public static void main(String[] args) {
        //重写EventBus的toString方法,使eventBus的名称为DEAD-EVENT-BUS
        final EventBus eventBus = new EventBus(){
            @Override public String toString() {
                return "DEAD-EVENT-BUS";
            }
        };
        DeadEventListener deadEventListener = new DeadEventListener();
        eventBus.register(deadEventListener);
        eventBus.post("DeadEventListener event");
        eventBus.post("DeadEventListener event");

    }
}

Output: DEAD-EVENT-BUS DeadEventListener event DEAD-EVENT-BUS DeadEventListener event

EventBus之异常处理

在默认情况下,EventBus不会对异常信息进行处理,异常信息也不会终止EventBus的运行,只会简单的打印出异常堆栈信息。

定义一个Listener:

代码语言:javascript
复制
public class ExceptionListener {

    private final static Logger LOGGER = LoggerFactory.getLogger(ExceptionListener.class);

    @Subscribe
    public void m1(final String event){
        if (LOGGER.isInfoEnabled()){
            LOGGER.info("Received event [{}] and will take m1", event);
        }
    }
    @Subscribe
    public void m2(final String event){
        if (LOGGER.isInfoEnabled()){
            LOGGER.info("Received event [{}] and will take m2", event);
        }
    }
    @Subscribe
    public void m3(final String event){
        throw new RuntimeException();
    }
}

定义一个EventBus:

代码语言:javascript
复制
public class ExceptionEventBusExample {
    public static void main(String[] args) {
        //在默认情况下,EventBus不会对异常信息进行处理,异常信息也不会终止EventBus的运行,只会简单的打印出异常堆栈信息。
        //在EventBus构造函数中传入SubscriberExceptionHandler来对异常信息进行处理
        //下面是通过lambda表达式来实现SubscriberExceptionHandler接口
        final EventBus eventBus = new EventBus((exception,context) -> {
            System.out.println(context.getEvent());//Exception event
            System.out.println(context.getEventBus());//defalut
            System.out.println(context.getSubscriber());//ExceptionListener
            System.out.println(context.getSubscriberMethod());//m3
        });
        eventBus.register(new ExceptionListener());
        eventBus.post("Exception event");
    }
}

Output: 2018-06-03 18:16:25:INFO main com.guava.eventbus.listeners.ExceptionListener - Received event [Exception event] and will take m2 Exception event EventBus{default} com.guava.eventbus.listeners.ExceptionListener@7a0ac6e3 public void com.guava.eventbus.listeners.ExceptionListener.m3(java.lang.String) 2018-06-03 18:16:25:INFO main com.guava.eventbus.listeners.ExceptionListener - Received event [Exception event] and will take m1

结论:在默认情况下,EventBus不会对异常信息进行处理,异常信息也不会终止EventBus的运行,只会简单的打印出异常堆栈信息。可以在EventBus构造函数中传入一个SubscriberExceptionHandler对象来对异常信息进行处理。上述代码是通过lambda表达式来实现了一个SubscriberExceptionHandler接口。

本文源代码地址: EventBus

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2018年06月03日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • EventBus基本用法
    • 1. 创建Listener
      • 2. 创建EventBus并发送消息
      • Listener之间的继承关系
      • Subscriber
        • 不同类型参数的Subscribe
        • event
          • 继承关系的event
            • DeadEvent
            • EventBus之异常处理
            相关产品与服务
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档