前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Guava中的异步事件处理方案很优雅!

Guava中的异步事件处理方案很优雅!

作者头像
Bug开发工程师
发布2020-02-19 21:37:55
2.7K0
发布2020-02-19 21:37:55
举报
文章被收录于专栏:码农沉思录码农沉思录

点击上方“码农沉思录”,选择“设为星标”

优质文章,及时送达

简述

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

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

EventBus基本用法

1. 创建Listener

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

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方法即可向其发送消息。

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

Listener之间的继承关系

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

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

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。

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:

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

1. 不同类型参数的Subscribe

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

定义Subscribe

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:

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

结果:

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

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

event

1. 继承关系的event

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:

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:

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

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

DeadEvent

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

创建listener:

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:

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

    }
}

EventBus之异常处理

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

定义一个Listener:

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:

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

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

祝大家在2020年工作顺路,家庭幸福,合家团圆

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-02-02,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 码农沉思录 微信公众号,前往查看

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

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

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