Java-类库-Guava-EventBus

  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 class TestEvent {
    private final int message;
    public TestEvent(int message) {
        this.message = message;
        System.out.println("event message:"+message);
    }
    public int getMessage() {
        return message;
    }
}

 消息接受类:
 

public class EventListener {
    public int lastMessage = 0;

    @Subscribe
    public void listen(TestEvent event) {
        lastMessage = event.getMessage();
        System.out.println("Message:"+lastMessage);
    }

    public int getLastMessage() {
        return lastMessage;
    }
}

测试类及输出结果:

public class TestEventBus {
    @Test
    public void testReceiveEvent() throws Exception {

        EventBus eventBus = new EventBus("test");
        EventListener listener = new EventListener();

        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:200
Message:200
event message:300
Message:300
event message:400
Message:400
LastMessage:400

 MultiListener的使用:
 只需要在要订阅消息的方法上加上@Subscribe注解即可实现对多个消息的订阅,代码如下:
 

public class MultipleListener {
    public Integer lastInteger;
    public Long lastLong;  

    @Subscribe
    public void listenInteger(Integer event) {
        lastInteger = event;
        System.out.println("event Integer:"+lastInteger);
    }  

    @Subscribe
    public void listenLong(Long event) {
        lastLong = event;
        System.out.println("event Long:"+lastLong);
    }  

    public Integer getLastInteger() {
        return lastInteger;
    }  

    public Long getLastLong() {
        return lastLong;
    }
}
public class TestMultipleEvents {
    @Test
    public void testMultipleEvents() throws Exception {  

        EventBus eventBus = new EventBus("test");
        MultipleListener multiListener = new MultipleListener();  

        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:100
event Integer:200
event Integer:300
event Long:800
event Long:800990
event Long:800882934
LastInteger:300
LastLong:800882934

 Dead Event:

  如果EventBus发送的消息都不是订阅者关心的称之为Dead Event。实例如下
  

public class DeadEventListener {
    boolean notDelivered = false;  

    @Subscribe
    public void listen(DeadEvent event) {  

        notDelivered = true;
    }  

    public boolean isNotDelivered() {
        return notDelivered;
    }
}
public class DeadEventListener {
    boolean notDelivered = false;  

    @Subscribe
    public void listen(DeadEvent event) {  

        notDelivered = true;
    }  

    public boolean isNotDelivered() {
        return notDelivered;
    }
}

说明:如果没有消息订阅者监听消息, EventBus将发送DeadEvent消息,这时我们可以通过log的方式来记录这种状态。

  Event的继承:

  如果Listener A监听Event A, 而Event A有一个子类Event B, 此时Listener A将同时接收Event A和B消息,实例如下:

  Listener 类:
  

public class NumberListener {  

    private Number lastMessage;  

    @Subscribe
    public void listen(Number integer) {
        lastMessage = integer;
        System.out.println("Message:"+lastMessage);
    }  

    public Number getLastMessage() {
        return lastMessage;
    }
}  

public class IntegerListener {  

    private Integer lastMessage;  

    @Subscribe
    public void listen(Integer integer) {
        lastMessage = integer;
        System.out.println("Message:"+lastMessage);
    }  

    public Integer getLastMessage() {
        return lastMessage;
    }
}  
public class TestEventsFromSubclass {
    @Test
    public void testEventsFromSubclass() throws Exception {  

        EventBus eventBus = new EventBus("test");
        IntegerListener integerListener = new IntegerListener();
        NumberListener numberListener = new NumberListener();
        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:100
Message:100
integerListener message:100
numberListener message:100
Message:200
integerListener message:100
numberListener message:200

说明:在这个方法中,我们看到第一个事件(新的整数(100))是收到两个听众,但第二个(新长(200 l))只能到达NumberListener作为整数一不是创建这种类型的事件。可以使用此功能来创建更通用的监听器监听一个广泛的事件和更详细的具体的特殊的事件。

  一个综合实例:

public class UserThread extends Thread {
    private Socket connection;
    private EventBus channel;
    private BufferedReader in;
    private PrintWriter out;

    public UserThread(Socket connection, EventBus channel) {
        this.connection = connection;
        this.channel = channel;
        try {
            in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
            out = new PrintWriter(connection.getOutputStream(), true);
        } catch (IOException e) {
            e.printStackTrace();
            System.exit(1);
        }
    }

    @Subscribe
    public void recieveMessage(String message) {
        if (out != null) {
            out.println(message);
            System.out.println("recieveMessage:"+message);
        }
    }

    @Override
    public void run() {
        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;
import java.net.ServerSocket;
import java.net.Socket;

import com.google.common.eventbus.EventBus;

public class EventBusChat {
    public static void main(String[] args) {
        EventBus channel = new EventBus();
        ServerSocket socket;
        try {
            socket = new ServerSocket(4444);
            while (true) {
                Socket connection = socket.accept();
                UserThread newUser = new UserThread(connection, channel);
                channel.register(newUser);
                newUser.start();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

说明:用telnet命令登录:telnet 127.0.0.1 4444 ,如果你连接多个实例你会看到任何消息发送被传送到其他实例

时间: 2025-01-30 14:38:16

Java-类库-Guava-EventBus的相关文章

2016 年排名 Top 100 的 Java 类库

我们分析了GitHub中47,251个依赖,从中找出了排名前一百的Java类库,让我们看看谁在前面,谁在后面. 我们在漫长的周末的消遣方式就是浏览GitHub并且搜索流行的Java类库.我们决定把其中的乐趣与结果分享给你. 我们分析了GitHub中排名前3,862个项目中的47,251个导入语句,其中有12,059个Java类库被依赖.我们从这个列表中提取出前一百并把结果分享给你. 最受欢迎的前20个Java类库 和上次分析结果一致,junit依旧是GitHub中最受欢迎的类库.Java中的日志

PHP如何调用JAVA 类库

JAVA是个非常强大的编程利器,它的扩展库也是非常的有用,这篇教程,主要讲述怎样使用PHP调用功能强大的JAVA 类库(classes).为了方便你的学习,这篇教程将包括JAVA的安装及一些基本的例子. Windows下的安装 第一步:安装JDK,这是非常容易的,你只需一路回车的安装好.然后做好以下步骤. 在 Win9x 下加入 :"PATH=%PATH%;C:\jdk1.2.2\bin" 到AUTOEXEC.BAT文件中 在 NT 下加入 ";C:\jdk1.2.2\bin

怎样使用PHP调用功能强大的JAVA 类库

JAVA是个非常强大的编程利器,它的扩展库也是非常的有用,这篇教程,主要讲述怎样使用PHP调用功能强大的JAVA 类库(classes).为了方便你的学习,这篇教程将包括JAVA的安装及一些基本的例子. windows下的安装 第一步:安装JDK,这是非常容易的,你只需一路回车的安装好.然后做好以下步骤. 在 Win9x 下加入 :"PATH=%PATH%;C:\jdk1.2.2\bin" 到AUTOEXEC.BAT文件中 在 NT 下加入 ";C:\jdk1.2.2\bin

怎样使用PHP调用功能强大的JAVA类库

JAVA是个非常强大的编程利器,它的扩展库也是非常的有用,这篇教程,主要讲述怎样使用PHP调用功能强大的JAVA 类库(classes).为了方便你的学习,这篇教程将包括JAVA的安装及一些基本的例子. windows下的安装 第一步:安装JDK,这是非常容易的,你只需一路回车的安装好.然后做好以下步骤. 在 Win9x 下加入 :"PATH=%PATH%;C:\jdk1.2.2\bin" 到AUTOEXEC.BAT文件中 在 NT 下加入 ";C:\jdk1.2.2\bin

从Java类库看设计模式(2)

在上一部分的内容中,我们讲到什么是模式,什么是设计模式,以及对一个设计模式 Observer的详细阐叙.相信大家对于模式的概念应该是比较的理解了.这部分及以后的内容 ,将会步入正题,从Java类库的分析入手,来阐叙设计模式是如何应用到一个完美的设计中 的.实际上,Java类库非常的庞杂,这儿不可能把所有能够找到的设计模式的例子一一列举 ,只是找了一些容易发现的例子.实际上也没有必要,因为只要对一个设计模式有足够的理 解,对于它的具体应用而言,倒是一件不是很困难的事情. Command模式 在设计

从Java类库看设计模式(1)

在这一部分的内容中,介绍的是一个相对简单但功能强大的模式:Observer模式.希望通 过这部分地叙述,大家看了之后,能够对设计模式有一个比较全面地,感性的认识. 很多时候,对于一个设计来说(软件上的,建筑上的,或者它他工业上的),经验是至关 重要的.好的经验给我们以指导,并节约我们的时间:坏的经验则给我们以借鉴,可以减少 失败的风险.然而,从知识层面上来讲,经验只是作为一种工作的积累而存在于个人的大脑 中的,很难被传授或者记录.为了解决这样的问题,人们提出了所谓的模式的概念.所谓模 式,是指在

Guava - EventBus(事件总线)

Guava在guava-libraries中为我们提供了事件总线EventBus库,它是事件发布订阅模式的实现,让我们能在领域驱动设计(DDD)中以事件的弱引用本质对我们的模块和领域边界很好的解耦设计. 不再多的废话,直奔Guava EventBus主题.首先Guava为我们提供了同步事件EventBus和异步实现AsyncEventBus两个事件总线,他们都不是单例的,官方理由是并不想我们我们的使用方式.当然如果我们想其为单例,我们可以很容易封装它,一个单例模式保证只创建一个实例就对了. 下面

Thumbnailator v0.3.0发布 图像缩略图的Java类库

Thumbnailator 是一个用来生成图像缩略图的 Java 类库,通过很简单的代码即可生成图片缩略图,也可直接对一整个目录的图片生成缩略图. File originalhttp://www.aliyun.com/zixun/aggregation/19352.html">File = new File("original.jpg");File thumbnailFile = new File("thumbnail.jpg");Thumbnail

ExpressionJ v0.3.4发布 解析简单算术表达式的Java类库

ExpressionJ 是一个用来解析简单的算术表达式的 Java 类库. ExpressionJ is a Java library allowing to interpret simple numeric expressions, which may be used in all applications which have to combine numeric http://www.aliyun.com/zixun/aggregation/9541.html">values, bu

ExpressionJ v0.3.3发布 Java类库数字算术表达式

ExpressionJ是一个Java类库用于解析简单的数字算术表达式. 该版本修复了重置 FunctionsDefinitions的bug. This project was registered on SourceForge.net on Dec 31, 2010, and is described by the project team as follows: ExpressionJ is a Java library allowing to interpret simple numeric