查看原文
其他

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

作者:edison_kwok 

来源:https://urlify.cn/3yaEZr

# 简述


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接口。


热文推荐
推荐几个免费的学习网站
一年多远程工作的酸甜苦辣,只有自己才知道...
说实话,90%的年轻人对IT一无所知?




觉得不错,请给个「在看」

分享给你的朋友!


点我,查看更多精彩文章。

    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存