EventBus使用详解的

|▌冷眼眸甩不掉的悲伤 提交于 2019-11-27 00:14:02

在使用ApplicationEvent和Listener快速实现业务解耦中提到了用Spring提供的观察者设计模式完成系统内部逻辑解耦。本文将介绍Google-Guava中的一种消息发布-订阅类库——EventBus。
EventBus 是Google.Guava提供的消息发布-订阅类库,它实现了观察者设计模式,消息通知负责人通过EventBus去注册/注销观察者,最后由消息通知负责人给观察者发布消息。
前提:在pom.xml中引入guava包

   <dependency>
            <groupId>com.google.guava</groupId>
            <artifactId>guava</artifactId>
            <version>27.0-jre</version>
        </dependency>

新建类:
相当于注册中心:注册执行都是通过这个类:


import com.google.common.eventbus.EventBus;


public class EventBusCenter {

    private static EventBus eventBus = new EventBus();

    private EventBusCenter() {

    }

    public static EventBus getInstance() {
        return eventBus;
    }

    public static void register(Object obj) {
        eventBus.register(obj);
    }

    public static void unregister(Object obj) {
        eventBus.unregister(obj);
    }

    public static void post(Object obj) {
        eventBus.post(obj);
    }

}  

兴建两个观察者:

import com.google.common.eventbus.Subscribe;

public class DataObserver1 {  
  
    /** 
     * 只有通过@Subscribe注解的方法才会被注册进EventBus 
     * 而且方法有且只能有1个参数 
     * 
     * @param msg 
     */  
    @Subscribe
    public void func(String msg) {
        System.out.println("String msg: " + msg);  
    }  
  
}  

import com.google.common.eventbus.Subscribe;

/**
 * Created by zhangzh on 2017/1/10. 
 */  
public class DataObserver2 {  
    /** 
     * post() 不支持自动装箱功能,只能使用Integer,不能使用int,否则handlersByType的Class会是int而不是Intege 
     * 而传入的int msg参数在post(int msg)的时候会被包装成Integer,导致无法匹配到 
     */  
    @Subscribe
    public void func(Integer msg) {  
        System.out.println("Integer msg: " + msg);  
    }  
}  

可以看到通过 @Subscribe注解只能有一个参数,如果是两个参数就会报错,只能有一个参数:

Exception in thread "main" com.google.common.util.concurrent.UncheckedExecutionException: java.lang.IllegalArgumentException: Method public void com.study.eventbus.DataObserver1.func(java.lang.String,java.lang.String) has @Subscribe annotation but has 2 parameters.Subscriber methods must have exactly 1 parameter.
	at com.google.common.cache.LocalCache$Segment.get(LocalCache.java:2050)
	at com.google.common.cache.LocalCache.get(LocalCache.java:3952)
	at com.google.common.cache.LocalCache.getOrLoad(LocalCache.java:3974)
	at com.google.common.cache.LocalCache$LocalLoadingCache.get(LocalCache.java:4958)
	at com.google.common.cache.LocalCache$LocalLoadingCache.getUnchecked(LocalCache.java:4964)
	at com.google.common.eventbus.SubscriberRegistry.getAnnotatedMethods(SubscriberRegistry.java:173)
	at com.google.common.eventbus.SubscriberRegistry.findAllSubscribers(SubscriberRegistry.java:164)
	at com.google.common.eventbus.SubscriberRegistry.register(SubscriberRegistry.java:74)
	at com.google.common.eventbus.EventBus.register(EventBus.java:186)
	at com.study.eventbus.EventBusCenter.register(EventBusCenter.java:21)
	at com.study.eventbus.Test.main(Test.java:13)
Caused by: java.lang.IllegalArgumentException: Method public void com.study.eventbus.DataObserver1.func(java.lang.String,java.lang.String) has @Subscribe annotation but has 2 parameters.Subscriber methods must have exactly 1 parameter.
	at com.google.common.base.Preconditions.checkArgument(Preconditions.java:412)
	at com.google.common.eventbus.SubscriberRegistry.getAnnotatedMethodsNotCached(SubscriberRegistry.java:184)
	at com.google.common.eventbus.SubscriberRegistry.access$000(SubscriberRegistry.java:54)
	at com.google.common.eventbus.SubscriberRegistry$1.load(SubscriberRegistry.java:154)
	at com.google.common.eventbus.SubscriberRegistry$1.load(SubscriberRegistry.java:151)
	at com.google.common.cache.LocalCache$LoadingValueReference.loadFuture(LocalCache.java:3528)
	at com.google.common.cache.LocalCache$Segment.loadSync(LocalCache.java:2277)
	at com.google.common.cache.LocalCache$Segment.lockedGetOrLoad(LocalCache.java:2154)
	at com.google.common.cache.LocalCache$Segment.get(LocalCache.java:2044)
	... 10 more

然后编写测试类:

/** 
 * Created by zhangzh on 2017/1/10. 
 */  
public class Test {  
  
    public static void main(String[] args) throws InterruptedException {  
  
        DataObserver1 observer1 = new DataObserver1();  
        DataObserver2 observer2 = new DataObserver2();  
  
        EventBusCenter.register(observer1);  
        EventBusCenter.register(observer2);  
  
        System.out.println("============   start  ====================");  
  
        // 只有注册的参数类型为String的方法会被调用  
        EventBusCenter.post("post string method");  
        EventBusCenter.post(123);  
  
        System.out.println("============ after unregister ============");  
        // 注销observer2  
        EventBusCenter.unregister(observer2);  
        EventBusCenter.post("post string method");  
        EventBusCenter.post(123);  
  
        System.out.println("============    end           =============");  
    }  
}  

在这里插入图片描述
总结:
EventBus的使用注意问题:

  • 代码可读性很差,项目中使用的时候,从post的地方,查询handle使用,都是使用ide的搜索服务,问题很难定位,不如普通的接口调用方便查询;
  • 由于EventBus是将消息队列放入到内存中的,listener消费这个消息队列,故系统重启之后,保存或者堆积在队列中的消息丢失。

作者:jackcooper
链接:https://www.jianshu.com/p/93486a604c34
来源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!