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接口。
觉得不错,请给个「在看」
分享给你的朋友!