Guava-EventBus 詳解

   EventBus是一個事件(消息)發佈訂閱框架,使用了觀察者模式,可以同步也可以異步。選擇同步還是異步就根據個人場景來進行選擇。

AsyncEventBus就是異步的,是在EventBus的基礎上,加入了Executor來異步執行訂閱者處理事件的方法,這樣就不會因爲訂閱事件執行過慢而阻塞主線程,源碼如下:

@Beta
public class AsyncEventBus extends EventBus {
    public AsyncEventBus(String identifier, Executor executor) {
        super(identifier, executor, Dispatcher.legacyAsync(), LoggingHandler.INSTANCE);
    }

    public AsyncEventBus(Executor executor, SubscriberExceptionHandler subscriberExceptionHandler) {
        super("default", executor, Dispatcher.legacyAsync(), subscriberExceptionHandler);
    }

    public AsyncEventBus(Executor executor) {
        super("default", executor, Dispatcher.legacyAsync(), LoggingHandler.INSTANCE);
    }
}

先通過代碼看一下它簡單的用法:

事件處理器1:

public class EventApple {

    @Subscribe
    public void eat(String apple){
        System.out.println("吃"+apple);
    }


}

事件處理器2:

public class EventRun {

    @Subscribe
    public void run(Integer run){
        System.out.println("跑步第"+run+"名");
    }
}

    註冊事件處理器,發佈事件。

public class TestEventBus {

    public static void main (String[] args){
        EventBus eventBus=new EventBus();

        eventBus.register(new EventApple());
        eventBus.register(new EventRun());
        eventBus.post(5);
        eventBus.post("蘋果");

    }
}

輸出:

跑步第5名
吃蘋果

EventBus的基本用法就是:

1、創建EventBus對象,EventBus的構造函數,源碼如下:

    public EventBus() {
        this("default");
    }

    public EventBus(String identifier) {
        this(identifier, MoreExecutors.directExecutor(), Dispatcher.perThreadDispatchQueue(), EventBus.LoggingHandler.INSTANCE);
    }

    public EventBus(SubscriberExceptionHandler exceptionHandler) {
        this("default", MoreExecutors.directExecutor(), Dispatcher.perThreadDispatchQueue(), exceptionHandler);
    }

    EventBus(String identifier, Executor executor, Dispatcher dispatcher, SubscriberExceptionHandler exceptionHandler) {
        this.subscribers = new SubscriberRegistry(this);
        this.identifier = (String)Preconditions.checkNotNull(identifier);
        this.executor = (Executor)Preconditions.checkNotNull(executor);
        this.dispatcher = (Dispatcher)Preconditions.checkNotNull(dispatcher);
        this.exceptionHandler = (SubscriberExceptionHandler)Preconditions.checkNotNull(exceptionHandler);
    }

構造函數有三個:

第一個是:創建一個新的EventBus對象,默認名稱爲default

第二個是:使用指定的標識符創建一個新的EventBus

第三個shi :使用SubscriberExceptionHandler ,處理subscribers處理事件時拋出異常。

2、註冊事件處理器,源碼:

void register(Object listener) {
        Multimap<Class<?>, Subscriber> listenerMethods = this.findAllSubscribers(listener);

        Collection eventMethodsInListener;
        CopyOnWriteArraySet eventSubscribers;
        for(Iterator var3 = listenerMethods.asMap().entrySet().iterator(); var3.hasNext(); eventSubscribers.addAll(eventMethodsInListener)) {
            Entry<Class<?>, Collection<Subscriber>> entry = (Entry)var3.next();
            Class<?> eventType = (Class)entry.getKey();
            eventMethodsInListener = (Collection)entry.getValue();
            eventSubscribers = (CopyOnWriteArraySet)this.subscribers.get(eventType);
            if (eventSubscribers == null) {
                CopyOnWriteArraySet<Subscriber> newSet = new CopyOnWriteArraySet();
                eventSubscribers = (CopyOnWriteArraySet)MoreObjects.firstNonNull(this.subscribers.putIfAbsent(eventType, newSet), newSet);
            }
        }

    }
事件處理器中要被執行的事件,都需要使用@Subscribe註解,表示是註冊的事件。

3、發佈事件

 public void post(Object event) {
        Iterator<Subscriber> eventSubscribers = this.subscribers.getSubscribers(event);
        if (eventSubscribers.hasNext()) {
            this.dispatcher.dispatch(event, eventSubscribers);
        } else if (!(event instanceof DeadEvent)) {
            this.post(new DeadEvent(this, event));
        }

    }

發佈事件之後,就去註冊的事件處理器中查找有@Subscribe的註解的方法,找到對應參數類型的事件就執行。

如果在註冊的處理器中沒有找到發佈的事件,那麼EventBus就會把該事件包裝成個DeadEvent事件來重新發布,我們可以提供下面的事件處理來處理DeadEvent:

 @Subscribe
    public void onEvent(DeadEvent de) {
        System.out.println("發佈了錯誤的事件:" + de.getEvent());
    }

AsyncEventBus是異步的,只需要在AsyncEventBus的構造函數中添加Executor即可:

AsyncEventBus asyncEventBus=new AsyncEventBus(Executors.newFixedThreadPool(10));

其他操作和原始的EventBus是一樣的。


EventBus中默認的訂閱方式是線程不安全的,但是在異步調度的時候會自動將其包裝成線程安全的。對於一般的線程安全的實現上可以通過@AllowConcurrentEvents註解來標示。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章