EventBus
Guava提供的EventBus可以实现不同组件之间解耦,可以向EventBus上注册多个handler,然后通过向EventBus post数据匹配响应的handler,触发handler的处理。handler的执行有同步和异步两种方式。事实上,EventBus也是实现了fan-out模型的很好工具类。
EventBus使用只需三步:
- 创建EventBus实例
- 向EventBus实例注册handler
- 向EventBus提交数据
EventBus使用起来还是比较简单的,用一个例子就能演示EventBus的所有功能。代码如下:
public class GuavaEventBusTest {
private EventBus syncEventBus = new EventBus();
private AsyncEventBus asyncEventBus = new AsyncEventBus(Executors.newCachedThreadPool());
class SendMessage {
@Subscribe
public void send(Message message) throws InterruptedException {
Thread.sleep(2000);
System.out.println("send message :" + message.id + ": " + message.content);
}
}
class SendDB {
@Subscribe
public void send(Integer event) {
System.out.println("send to db: " + event);
}
}
class SendDB1 {
@Subscribe
public void send(Integer event) {
System.out.println("send to db1: " + event);
}
}
class Message {
int id;
String content;
public Message(String content, int id) {
this.content = content;
this.id = id;
}
}
/**
* 演示同步的EventBus,在post的时候,自动的类型匹配找对应的Subscriber
*/
@Test
public void test1() {
syncEventBus.register(new SendMessage());
syncEventBus.register(new SendDB());
syncEventBus.post("dianping"); //类型自动匹配
syncEventBus.post(new Message("hello world", 1));
syncEventBus.post(1);
}
/**
* 演示异步的EventBus,一定要注意这个bus的创建,这个是将消息的生产和处理彻底解耦了
*
* @throws InterruptedException
*/
@Test
public void test2() throws InterruptedException {
asyncEventBus.register(new SendMessage());
asyncEventBus.register(new SendDB());
asyncEventBus.register(new SendDB1());
asyncEventBus.post("dianping"); //类型自动匹配
asyncEventBus.post(new Message("hello world", 1));
asyncEventBus.post(1);
Thread.sleep(3000);
}
/**
* 演示在一个类中有多个Subscribe处理方法
*/
@Test
public void test3() {
MutilHandler mutilHandler = new MutilHandler();
asyncEventBus.register(mutilHandler);
asyncEventBus.post(1);//每个post都会占用AsyncEventBus的线程池中的一个线程
asyncEventBus.post(2);
asyncEventBus.post(new Message("zhangsan", 1));
asyncEventBus.post(new Message("lisi", 2));
}
/**
* 演示DeadEvent,在没有任何Event匹配上的时候,走DeadEvent
* 作为使用EventBus的良好习惯,永远将Bus上注册一个DeadEvent,并在其中记录日志(小范围使用可以不这么搞)
*/
@Test
public void test4() {
asyncEventBus.register(new MutilHandler());
asyncEventBus.register(new DeadEventHandler());
asyncEventBus.post(new Long(1));//没有任何Subscribe类型匹配上的话,就会调用DeadEvent
}
/**
* 演示类型匹配时,如果实参类型是Subscribe定义的形参类型的子类,依然能够匹配上
*/
@Test
public void test5() {
asyncEventBus.register(new StringHandler());
asyncEventBus.post(new String("zhangsan"));
asyncEventBus.post(new StringBuffer("lisi"));
}
class MutilHandler {
@Subscribe
public void handleInteger(Integer i) {
System.out.println(Thread.currentThread().getName() + ": handle integer " + i);
}
@Subscribe
public void handlerMessage(GuavaEventBusTest.Message message) {
System.out.println(Thread.currentThread().getName() + ": handle message " + message.content);
}
}
class DeadEventHandler {
@Subscribe
public void handleDeadEvent(DeadEvent event) {
System.out.println("dead event: " + event.getEvent());
}
}
class StringHandler {
@Subscribe
public void handleString(String s) {
System.out.println("handle string: " + s);
}
@Subscribe
public void handleCharSequence(CharSequence cs) {
System.out.println("handle CharSequence: " + cs);
}
}
}
定义了两种EventBus,同步的和异步的,异步EventBus需要知道handler执行的线程池。
test1演示了同步EventBus,代码syncEventBus.register(new SendMessage());
向EventBus注册了处理类。可以看出,成为一个处理类:
- 类名任意,不需要实现特定接口
- 类中的方法名任意,参数任意
- 处理方法需要@Subscribe注解
要求的确很低,只需要@Subscribe注解,其他没啥要求。代码syncEventBus.post("dianping")
向EventBus提交了一个数据,post方法只能接受一个Object类型的参数,多个参数封装成对象。只要和post提交的数据类型匹配的方法都会被执行,类型匹配是指:
- 处理方法参数的个数为1个
- 处理方法参数的类型和post数据相同或为它的父类
若提交的数据没有匹配任何处理方法的参数,则不会被任何方法处理。在test1中,字符串类型"dianping"就不会被任何方法接收处理。执行结果:
send message :1: hello world
send to db: 1
test2在test1的基础上增加一个SendDB1,并改成异步的EventBus,说明如果post的数据匹配多个处理方法,则每个方法都会收到数据并执行,同时可以看到异步执行的效果。结果如下:
send to db: 1
send to db1: 1
send message :1: hello world
test3在同一个类中定义了多个处理方法,并分别用@Subscribe注解,可以看到每个方法都会被触发执行,执行结果:
pool-1-thread-1: handle integer 1
pool-1-thread-2: handle integer 2
pool-1-thread-2: handle message zhangsan
pool-1-thread-1: handle message lisi
test4定义了一个DeadEventHandler,没有匹配任何处理方法的数据会触发这个方法执行,在方法中可以拿到这个数据,执行结果:
dead event: 1
test5定义了一个StringHandler,演示了参数为提交的数据类型父类,也可以被触发执行,因为CharSequence是StringBuffer的父类,所以post(new StringBuffer("lisi"))
也会触发它的执行,结果如下:
handle CharSequence: zhangsan
handle string: zhangsan
handle CharSequence: lisi