前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Guava之eventBus异步事件总线的使用及源码分析

Guava之eventBus异步事件总线的使用及源码分析

作者头像
克虏伯
发布2019-04-15 10:14:18
2.5K0
发布2019-04-15 10:14:18
举报
文章被收录于专栏:软件开发-青出于蓝

    最近使用guava的eventBus,记录下。

1、如何使用

List-1.1

代码语言:javascript
复制
import com.google.common.eventbus.AllowConcurrentEvents;
import com.google.common.eventbus.AsyncEventBus;
import com.google.common.eventbus.Subscribe;
import org.junit.Before;
import org.junit.Test;

import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

public class EventBusTest {
    private AsyncEventBus asyncEventBus;

    @Before
    public void before(){
        asyncEventBus=new AsyncEventBus(Executors.newFixedThreadPool(3));
        asyncEventBus.register(this);
    }

    @Subscribe
    @AllowConcurrentEvents
    public void subscribe(Object object){
        System.out.println("收到:"+object);
    }

    @Test
    public void test_sendMsg() throws InterruptedException {
        System.out.println("开始发送消息");
        asyncEventBus.post("这是消息");
        System.out.println("开始睡眠");
        TimeUnit.SECONDS.sleep(5L);
    }
}

    List-1.1中,方法subscribe是接收者,方法test_sendMsg中post消息后,方法subscribe就会收到消息。这是因为方法subscribe上有注解Subscribe。

    为什么要在方法subscribe上加上注解AllowConcurrentEvents,加上这个才能达到真正的异步,这要看底层源码,下面我们会来分析。

2、register方法底层实现

    AsyncEventBus的构造方法如下List-2.1所示

List-2.1

代码语言:javascript
复制
public AsyncEventBus(Executor executor) {
  super("default", executor, Dispatcher.legacyAsync(), LoggingHandler.INSTANCE);
}

    来看下register方法的实现,如下图2.1所示,步骤3中,会找到所有方法上有Subscribe注解的方法,在步骤6中,会判断方法上是否注解AllowConcurrentEvents,如果有,则返回Subscriber,如果没有则返回SynchronizedSubscriber。

                  图2.1 AsyncEventBus的register方法

    SynchronizedSubscriber和Subscriber的区别如下,SynchronizedSubscriber重复了父类的invokeSubscriberMethod,并加上了锁关键字synchronized,所以List-1.1中的方法上如果没有注解AllowConcurrentEvents,那么是不会真正的并发的,我看了网上的例子,很多描述的不全面。

    List-2.2

代码语言:javascript
复制
@VisibleForTesting
static final class SynchronizedSubscriber extends Subscriber {

  private SynchronizedSubscriber(EventBus bus, Object target, Method method) {
    super(bus, target, method);
  }

  @Override
  void invokeSubscriberMethod(Object event) throws InvocationTargetException {
    synchronized (this) {
      super.invokeSubscriberMethod(event);
    }
  }
}

3、post方法底层实现

                  图3.1 AsyncEventBus的post实现

    步骤6、7的代码如下List-3.1,可以看到List-2.2中涉及的invokeSubscriberMethod在这里使用。

List-3.1

代码语言:javascript
复制
final void dispatchEvent(final Object event) {
  executor.execute(
      new Runnable() {
        @Override
        public void run() {
          try {
            invokeSubscriberMethod(event);
          } catch (InvocationTargetException e) {
            bus.handleSubscriberException(e.getCause(), context(event));
          }
        }
      });
}

    guava提供了三个Dispatcher,上面使用了LegacyAsyncDispatcher,LegacyAsyncDispatcher的dispatch实现如下List-3.2所示,可以看到,是将event和subscriber放入到ConcurrentLinkedQueue中,之后再从queue中poll出来,再调用subscribe的dispatchEvent方法。为什么先放到queue中,之后在poll出来,这是有考虑的,是为了应用整体的吞吐量考虑。

List-3.2

代码语言:javascript
复制
private final ConcurrentLinkedQueue<EventWithSubscriber> queue =
    Queues.newConcurrentLinkedQueue();

@Override
void dispatch(Object event, Iterator<Subscriber> subscribers) {
  checkNotNull(event);
  while (subscribers.hasNext()) {
    queue.add(new EventWithSubscriber(event, subscribers.next()));
  }

  EventWithSubscriber e;
  while ((e = queue.poll()) != null) {
    e.subscriber.dispatchEvent(e.event);
  }
}

Reference:

  1. google guava版本27.0-jre源码

(adsbygoogle = window.adsbygoogle || []).push({});

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1、如何使用
  • 2、register方法底层实现
  • 3、post方法底层实现
  • Reference:
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档