zoukankan      html  css  js  c++  java
  • 使用Guava EventBus构建publish/subscribe系统

    Google的Guava类库提供了EventBus,用于提供一套组件内publish/subscribe的解决方案.事件总线EventBus,用于管理事件的注册和分发。在系统中,Subscribers会向EventBus注册自己感兴趣的事件,而publishers会将自己产生的事件发布给EventBus。在系统中,EventBus事件分发默认设置为串行的(可设置),我们在Subscribers中的事件处理速度要快,不要阻塞当前的事件纷发进程。

    创建EventBus实例

    EventBus提供两个构造函数,可用于创建Evnet实例,如下所示。

        @Test
        public void should_create_event_bus_instance() throws Exception {
            EventBus eventBus = new EventBus();
            //string构造参数,用于标识EventBus
            EventBus eventBus1 = new EventBus("My Event Bus");
        }
    

    Subscribe事件

    1. Subsciber对象需要定义handler method,用于接受并处理一个通知事件对象
    2. 使用Subscribe标签标识事件handler method
    3. Subscriber向EvenetBus注册,通过EventBus.register方法进行注册

    Post事件

    post一个事件很简单,只需要调用EventBus.post方法即可以实现。EventBus会调用Subscriber的handler method处理事件对象。

    定义handler Method

    方法接受一个事件类型对象,当publisher发布一个事件,eventbus会串行的处理event-handling method, 所以我们需要让event-handing method处理的速度快一些,通常我们可以通过多线程手段来解决延迟的问题。

    Concurrency

    EventBus可以通过使用AllowConcurrentEvent注解来实现并发调用handle method。当handler method被标记为AllowConcurrentEvent(replace Subscribe标签),我们认为handler Method是线程安全的。

    Code Sample

    例子中,我们使用cookie店为例,为了简单起见,系统中只定义了五个对象:

    1. EmptyEvent对象:用于表明CookieContaier cookie数量为0
    2. CookieContaier对象:用于Cookie的存储,当cookie数量为0时,会发布EmptyEvent事件
    3. CookieSeller: EmptyEvent事件订阅者
    4. CookieMailBoss:EmptyEvent事件订阅者
    5. HandlerService: 定义handler-method接口,使用@Subscribe标注
    public interface HandlerService {
        @Subscribe
        void handler(EmptyEvent emptyEvent);
    }
    
    public class CookieSeller implements HandlerService {
    
        public CookieSeller(EventBus eventBus) {
            eventBus.register(this);
        }
    
        public void handler(EmptyEvent emptyEvent) {
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(this.getClass().getName() + ":" + "receiving empty event");
        }
    }
    
    public class CookieMallBoss implements HandlerService {
    
        public CookieMallBoss(EventBus eventBus) {
            eventBus.register(this);
        }
    
        public void handler(EmptyEvent emptyEvent) {
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(this.getClass().getName() + ":" + "receiving empty event");
        }
    }
    

    getCookie函数,会计算事件触发publish时间

    
    public class CookieContainer {
        private EventBus eventBus;
        private AtomicInteger numberOfCookie = new AtomicInteger();
    
        public CookieContainer(EventBus eventBus) {
            this.eventBus = eventBus;
        }
    
        public void setNumberOfCookie(int intenger) {
            numberOfCookie.set(intenger);
        }
    
        public void getACookie() {
            if (numberOfCookie.get() == 0) {
                long start = System.currentTimeMillis();
                eventBus.post(new EmptyEvent());
                System.out.println("Publishing event time: " + (System.currentTimeMillis() - start) + " ms");
                return;
            }
            numberOfCookie.decrementAndGet();
            System.out.println("retrieve a cookie");
        }
    }
    
    
    public class EmptyEvent {
    
    }
    
    

    Code Test Case

    设置cookie数量为三,当第四次取cookie会触发empty事件,EventBus会串行的发布事件。

    
        @Test
        public void should_recv_event_message() throws Exception {
            EventBus eventBus = new EventBus();
            CookieContainer cookieContainer=new CookieContainer(eventBus);
            HandlerService cookieSeller = new CookieSeller(eventBus);
            HandlerService cookieMallBoss = new CookieMallBoss(eventBus);
    
            //设置cookie的数量为3
            cookieContainer.setNumberOfCookie(3);
            //用户取三次之后cookie数量为空
            cookieContainer.getACookie();
            cookieContainer.getACookie();
            cookieContainer.getACookie();
            System.out.println("=======再次取cookie, 触发Empty事件发布============");
            cookieContainer.getACookie();
        }
        
    

    测试结果如下所示,当第四次getCookie时,触发EmptyEvent事件发布。耗时为4013ms

    retrieve a cookie
    retrieve a cookie
    retrieve a cookie
    =======触发事件发布============
    com.mj.ele.guava.CookieMallBoss:receiving empty event
    com.mj.ele.guava.CookieSeller:receiving empty event
    Publishing event time: 4013 ms
    

    使用AllowConcurrentEvents标签取Subscribe,设置cookie数量为三,当第四次取cookie会触发empty事件,EventBus会并行的发布事件。

    修改Handler method接口,标记为@AllowConcurrentEvents

    public interface HandlerService {
        @AllowConcurrentEvents
        void handler(EmptyEvent emptyEvent);
    }
    

    测试代码和串行代码一致,测试结果如下所示,事件发布耗时只需1ms

    retrieve a cookie
    retrieve a cookie
    retrieve a cookie
    =======触发事件发布============
    Publishing event time: 1 ms
    

    Conclusion

    本文讲解了如何使用Guava的EventBus来构建publish/subscribe系统,分别给出了串行和并行发布的使用方法,希望能够给读者带来一些帮助和启发。

  • 相关阅读:
    第五周学习总结
    第四周学习总结
    第三周学习总结
    第二周学习总结
    读《程序是怎样跑起来的》第十二章有感
    读《程序是怎样跑起来的》第十一章有感
    读《程序是怎样跑起来的》第十章有感
    读《程序是怎样跑起来的》第九章有感
    《程序是怎样跑起来的》第九章
    《程序是怎样跑起来的》第八章
  • 原文地址:https://www.cnblogs.com/jun-ma/p/4852133.html
Copyright © 2011-2022 走看看