EventBus是Guava的事件处理机制,是设计模式中的观察者模式(生产/消费者编程模型)的优雅实现。对于事件监听和发布订阅模式,EventBus是一个非常优雅和简单解决方案,我们不用创建复杂的类和接口层次结构。
Observer模式是比较常用的设计模式之一,虽然有时候在具体代码里,它不一定叫这个名字,比如改头换面叫个Listener,但模式就是这个模式。手工实现一个Observer也不是多复杂的一件事,只是因为这个设计模式实在太常用了,Java就把它放到了JDK里面:Observable和Observer,从JDK 1.0里,它们就一直在那里。从某种程度上说,它简化了Observer模式的开发,至少我们不用再手工维护自己的Observer列表了。不过,如前所述,JDK里的Observer从1.0就在那里了,直到Java 7,它都没有什么改变,就连通知的参数还是Object类型。要知道,Java 5就已经泛型了。Java 5是一次大规模的语法调整,许多程序库从那开始重新设计了API,使其更简洁易用。当然,那些不做应对的程序库,多半也就过时了。这也就是这里要讨论知识更新的原因所在。今天,对于普通的应用,如果要使用Observer模式该如何做呢?答案是Guava的EventBus。
EventBus基本用法:
使用Guava之后, 如果要订阅消息, 就不用再继承指定的接口, 只需要在指定的方法上加上@Subscribe注解即可。代码如下:
消息封装类:
public classTestEvent {private final intmessage;public TestEvent(intmessage) {this.message =message;
System.out.println("event message:"+message);
}public intgetMessage() {returnmessage;
}
}
消息接受类:
public classEventListener {public int lastMessage = 0;
@Subscribepublic voidlisten(TestEvent event) {
lastMessage=event.getMessage();
System.out.println("Message:"+lastMessage);
}public intgetLastMessage() {returnlastMessage;
}
}
测试类及输出结果:
public classTestEventBus {
@Testpublic void testReceiveEvent() throwsException {
EventBus eventBus= new EventBus("test");
EventListener listener= newEventListener();
eventBus.register(listener);
eventBus.post(new TestEvent(200));
eventBus.post(new TestEvent(300));
eventBus.post(new TestEvent(400));
System.out.println("LastMessage:"+listener.getLastMessage());
;
}
}//输出信息
event message:200Message:200event message:300Message:300event message:400Message:400LastMessage:400
MultiListener的使用:
只需要在要订阅消息的方法上加上@Subscribe注解即可实现对多个消息的订阅,代码如下:
public classMultipleListener {publicInteger lastInteger;publicLong lastLong;
@Subscribepublic voidlistenInteger(Integer event) {
lastInteger=event;
System.out.println("event Integer:"+lastInteger);
}
@Subscribepublic voidlistenLong(Long event) {
lastLong=event;
System.out.println("event Long:"+lastLong);
}publicInteger getLastInteger() {returnlastInteger;
}publicLong getLastLong() {returnlastLong;
}
}
测试类:
public classTestMultipleEvents {
@Testpublic void testMultipleEvents() throwsException {
EventBus eventBus = new EventBus("test");
MultipleListener multiListener= newMultipleListener();
eventBus.register(multiListener);
eventBus.post(new Integer(100));
eventBus.post(new Integer(200));
eventBus.post(new Integer(300));
eventBus.post(new Long(800));
eventBus.post(new Long(800990));
eventBus.post(new Long(800882934));
System.out.println("LastInteger:"+multiListener.getLastInteger());
System.out.println("LastLong:"+multiListener.getLastLong());
}
}//输出信息
event Integer:100event Integer:200event Integer:300event Long:800event Long:800990event Long:800882934LastInteger:300LastLong:800882934
Dead Event:
如果EventBus发送的消息都不是订阅者关心的称之为Dead Event。实例如下:
public classDeadEventListener {boolean notDelivered = false;
@Subscribepublic voidlisten(DeadEvent event) {
notDelivered= true;
}public booleanisNotDelivered() {returnnotDelivered;
}
}
测试类:
public classTestDeadEventListeners {
@Testpublic void testDeadEventListeners() throwsException {
EventBus eventBus = new EventBus("test");
DeadEventListener deadEventListener= newDeadEventListener();
eventBus.register(deadEventListener);
eventBus.post(new TestEvent(200));
eventBus.post(new TestEvent(300));
System.out.println("deadEvent:"+deadEventListener.isNotDelivered());
}
}//输出信息
event message:200event message:300deadEvent:true
说明:如果没有消息订阅者监听消息, EventBus将发送DeadEvent消息,这时我们可以通过log的方式来记录这种状态。
Event的继承:
如果Listener A监听Event A, 而Event A有一个子类Event B, 此时Listener A将同时接收Event A和B消息,实例如下:
Listener 类:
public classNumberListener {privateNumber lastMessage;
@Subscribepublic voidlisten(Number integer) {
lastMessage=integer;
System.out.println("Message:"+lastMessage);
}publicNumber getLastMessage() {returnlastMessage;
}
}public classIntegerListener {privateInteger lastMessage;
@Subscribepublic voidlisten(Integer integer) {
lastMessage=integer;
System.out.println("Message:"+lastMessage);
}publicInteger getLastMessage() {returnlastMessage;
}
}
测试类:
public classTestEventsFromSubclass {
@Testpublic void testEventsFromSubclass() throwsException {
EventBus eventBus = new EventBus("test");
IntegerListener integerListener= newIntegerListener();
NumberListener numberListener= newNumberListener();
eventBus.register(integerListener);
eventBus.register(numberListener);
eventBus.post(new Integer(100));
System.out.println("integerListener message:"+integerListener.getLastMessage());
System.out.println("numberListener message:"+numberListener.getLastMessage());
eventBus.post(new Long(200L));
System.out.println("integerListener message:"+integerListener.getLastMessage());
System.out.println("numberListener message:"+numberListener.getLastMessage());
}
}//输出类
Message:100Message:100integerListener message:100numberListener message:100Message:200integerListener message:100numberListener message:200
说明:在这个方法中,我们看到第一个事件(新的整数(100))是收到两个听众,但第二个(新长(200 l))只能到达NumberListener作为整数一不是创建这种类型的事件。可以使用此功能来创建更通用的监听器监听一个广泛的事件和更详细的具体的特殊的事件。
一个综合实例:
public class UserThread extendsThread {privateSocket connection;privateEventBus channel;privateBufferedReader in;privatePrintWriter out;publicUserThread(Socket connection, EventBus channel) {this.connection =connection;this.channel =channel;try{
in= new BufferedReader(newInputStreamReader(connection.getInputStream()));
out= new PrintWriter(connection.getOutputStream(), true);
}catch(IOException e) {
e.printStackTrace();
System.exit(1);
}
}
@Subscribepublic voidrecieveMessage(String message) {if (out != null) {
out.println(message);
System.out.println("recieveMessage:"+message);
}
}
@Overridepublic voidrun() {try{
String input;while ((input = in.readLine()) != null) {
channel.post(input);
}
}catch(IOException e) {
e.printStackTrace();
}//reached eof
channel.unregister(this);try{
connection.close();
}catch(IOException e) {
e.printStackTrace();
}
in= null;
out= null;
}
}
mport java.io.IOException;importjava.net.ServerSocket;importjava.net.Socket;importcom.google.common.eventbus.EventBus;public classEventBusChat {public static voidmain(String[] args) {
EventBus channel= newEventBus();
ServerSocket socket;try{
socket= new ServerSocket(4444);while (true) {
Socket connection=socket.accept();
UserThread newUser= newUserThread(connection, channel);
channel.register(newUser);
newUser.start();
}
}catch(IOException e) {
e.printStackTrace();
}
}
}
说明:用telnet命令登录:telnet 127.0.0.1 4444 ,如果你连接多个实例你会看到任何消息发送被传送到其他实例。