`
uule
  • 浏览: 6351995 次
  • 性别: Icon_minigender_1
  • 来自: 一片神奇的土地
社区版块
存档分类
最新评论

用guava实现简单的事件驱动

 
阅读更多

Guava的EventBus可以简化生产/消费模型。EventBus通过非常简单的方式,实现了观察者模式中的监听注册,事件分发。有了这个玩意,真的可以替换Observer模式了

 

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。

 

import com.google.common.eventbus.DeadEvent;

import com.google.common.eventbus.Subscribe;

 

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 TestDeadEventListeners {
    @Test  
    public void testDeadEventListeners() throws Exception {  
       
        EventBus eventBus = new EventBus("test");               
        DeadEventListener deadEventListener = new DeadEventListener();  
        eventBus.register(deadEventListener);  

        eventBus.post(new TestEvent(200));         
        eventBus.post(new TestEvent(300));        
       
        System.out.println("deadEvent:"+deadEventListener.isNotDelivered());

    }  
}

 

//输出信息

event message:200

event message:300

deadEvent:true

 

  说明:如果没有消息订阅者监听消息, 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;
    }
}

 

import 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 ,如果你连接多个实例你会看到任何消息发送被传送到其他实例。

 

另参考:Guava的生产/消费模型 —— EventBus

分享到:
评论

相关推荐

    guava-18.0(guava-18.0.jar和guava-18.0-sources.jar)

    8. **事件监听**:Guava的EventBus可以方便地实现发布/订阅模式,简化事件驱动的编程。 9. **枚举集与常量**:Guava提供了ImmutableEnumSet和ImmutableSet.of()等方法,创建不可变且高效的枚举集合。 `guava-18.0-...

    guava-jdk5

    8. **事件监听**:Guava的 EventBus 使得事件驱动编程在Java 5环境下变得可能,它允许组件之间松散耦合,通过发布和订阅事件来进行通信。 9. **运行时类型信息**:Guava提供了TypeToken和Types等工具类,帮助开发者...

    SpringBoot+EventBus使用教程示例代码

    在本文中,我们将深入探讨如何在SpringBoot应用中使用EventBus,这是一个基于Guava库的事件总线系统。EventBus的引入使得松耦合的...同时,配合SpringBoot的其他特性,如自动配置和AOP,可以进一步优化事件驱动架构。

    跟着 Guava、Spring 学习如何设计观察者模式.doc

    这种模式常用于创建事件驱动的系统,使得多个组件能够对特定事件作出响应。在Java中,Guava和Spring框架都提供了实现观察者模式的工具。 Guava的EventBus是观察者模式的一个实例,它简化了事件发布和订阅的过程。...

    第七章 企业项目开发--本地缓存guava cache1

    但是,需要注意的是,当数据库数据发生变化时,需要同步更新缓存,这通常可以通过事件驱动或定时任务实现。 总结,Guava Cache是Java开发中实现本地缓存的一个强大工具,它的灵活性和丰富的特性使得缓存管理变得...

    Node.js-EventBusOttoRxBus事件总线使用

    总的来说,虽然标题中的"Node.js-EventBusOttoRxBus事件总线使用"可能与Android开发更相关,但我们可以看到在Android领域,EventBus、Otto和RxBus是实现组件间通信的重要工具。而在Node.js中,我们可以使用内置的...

    Java Event Bus 事件监听器的应用

    在Java编程中,事件驱动模型是一种常见的设计模式,它使得组件之间可以相互通信而无需直接耦合。Event Bus(事件总线)是这种模式的一种实现,常用于Android和Java桌面应用。本文将深入探讨Java Event Bus的原理、...

    基于Java的多播事件总线 Avis.zip

    事件驱动架构(Event-Driven Architecture, EDA)是现代软件设计的一种常见模式,特别适用于分布式系统和微服务环境。Avis作为事件总线,扮演着核心角色,它连接发布者(Producer)和订阅者(Consumer),使得不同...

    组件模型与双事件处理线程

    Guava库提供了EventBus,可以帮助实现事件驱动编程;而在多线程处理方面,Java的ExecutorService和CompletableFuture等工具类能帮助我们优雅地管理线程和异步任务。 总的来说,组件模型和双事件处理线程是构建高...

    seleunim的jar包与chromdriver驱动

    当涉及到更复杂的交互,例如处理JavaScript事件、模拟用户操作或者等待特定元素加载时,Selenium提供了丰富的API供你使用。例如,可以使用`WebDriverWait`来等待某个条件满足,或者使用`ActionChains`来模拟鼠标和...

    Android的mvp模式+otto消息总线源码

    Otto是由Square公司开发的一个基于Google Guava库的事件总线,用于简化Android应用中的组件间通信。在大型项目中,组件间的通信可能会变得复杂,Otto提供了一种发布/订阅的方式来解决这个问题。 1. **发布(Publish...

    基于Java的实例源码-仿千千静听音乐播放器源代码.zip

    事件驱动编程是Java GUI应用的基础,它涉及到ActionListener和MouseListener等接口的实现。例如,当用户点击播放按钮时,对应的ActionListener会被触发,执行播放音乐的方法。同样,当用户在进度条上拖动时,...

    java_design_mode_pubsub.rar

    这种模式常用于实现事件驱动的系统,使得多个对象能够同步地接收到某个对象状态变化的信息。 在Java中,观察者模式的实现主要依赖于`java.util.Observable`和`java.util.Observer`这两个类。`Observable`类代表被...

    基于redis的二级缓存

    为此,可以采用事件驱动的方式,监听数据库的变更事件,触发相应的缓存清理或更新操作。 此外,优化Redis缓存的过期策略也是提高系统稳定性的关键。可以选择设置TTL(Time To Live)让缓存自动过期,或者根据LRU...

    基于 Java 13 实现的游戏服务器框架.zip

    - **Netty 框架**:作为Java领域最流行的网络编程库,Netty提供了一套完整的异步事件驱动的网络应用程序框架,可以快速构建高性能的游戏服务器。 3. **并发处理**: - **线程池**:使用ExecutorService创建线程池...

    future:Java、Guava 和 Scala 中的 Furures 和 promise

    这为异步编程提供了更加灵活的事件驱动模型。 Scala 的 Futures 和 Promises 则是其强大的 Actor 模型和响应式编程的一部分。Scala 的 `Future` 类代表一个异步操作的结果,类似于 Java 和 Guava,但它提供了更多的...

    nox-bus:异步事件总线

    在事件驱动的架构中,事件总线是一种通信机制,允许组件之间通过发布和订阅事件来解耦。传统的事件总线通常采用同步方式,即发布事件后,订阅者会立即处理事件,这可能导致阻塞主线程,影响应用性能。而nox-bus作为...

    JavaEnterprise原始企业开发servlet+jsp实现系统用户注册 jar包

    在Java企业级开发中,Servlet和JSP是两种核心的技术,它们被广泛应用于构建Web...配合适当的jar包,如Servlet和JSP API、JDBC驱动以及辅助库,可以实现与数据库交互、用户界面动态生成等功能,满足企业级应用的需求。

    行业分类-设备装置-一种接口调用的缓存实现方法.zip

    常见的有定时更新、事件驱动更新、版本号校验等。 - **缓存过期策略**:设定合理的过期时间,避免长时间未更新的缓存导致数据陈旧。 - **并发控制**:在多线程环境下,如何保证缓存操作的线程安全,防止数据一致性...

    java开源包3

    WebSocket4J 是一个用 Java 实现的 WebSocket 协议的类库,可使用 Java 来构建交互式 Web 应用。WebSocket4J 并未实现客户端通讯协议,所以不能用它来连接 WebSocket 服务器。 Struts验证码插件 JCaptcha4Struts2 ...

Global site tag (gtag.js) - Google Analytics