java event 异步_Java guava中的异步事件处理方案 eventBus

一、简述

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

2adab07d399116981aca4a9c0ade3364.png

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

}

}

c6a7341c2f514dbebec54b09dac4b13f.png

b4dc047a434dac9d0c3036faf0b0456f.png

三、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);

}

}

3a579871ae80649156d14d7d30c3bbe8.png

结果:

0cfc12e05d7a08aee002932efce32280.png

结论: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");

}

}

13307a445afbb0afae89c0c58ab70fdb.png

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值