Guava包学习--EventBus
之前没用过这个EventBus,然后看了一下EventBus的源码也没看明白,(-__-)b。反正大概就是弄一个优雅的方式实现了观察者模式吧。慢慢深入学习一下。
观察者模式其实就是生产者消费者的一个变种,就是一边有变化,然后有一个中介,也就是观察者去告诉消费者说:我说哥们啊,他们那边又变了,咱也跟着变吧!
然后观察者要么就是一个抽象类或者一个接口,里面有个update方法,需要每个处理的实例去实现,然后变化的那方持有这些实例,然后挨个去通知。
所以你也看到了,这个持有操作其实就是很不优雅的操作,所以我们用EventBus来看下这个地方到底是怎么实现的优雅的:
可以看到其实Guava中的EventBus的代码很少,只有几个类和注解。
注解有俩个:AllowConcurrentEvents和Subscribe,@AllowConcurrentEvents代表使用线程安全方式获得通知和@Subscribe代表这是一个订阅者,这俩注解和一起使用。
EventBus也就是观察者角色类有两个 EventBus和AsyncEventBus,前面是同步消息,后面支持异步消息。
DeadEvent是指没人关心的消息,可以做一下特殊处理,这个还是很有用,你可以获得有哪些消息根本没人消费过。
Subscriber订阅者对象,具体是哪个EventBus、哪个Listener、哪个方法 3者共同决定一个Subcriber
Dispatcher分发消息给上面那个(那些)Subscriber
SubscriberExceptionContext 订阅者抛出的异常上下文
SubscriberExceptionHandler 接口,处理订阅者抛出的异常
SubscriberRegistry 订阅动作,处理订阅者注册到一个EventBus的动作
我们来测试一下代码:
public class EventBusMain { static final EventBus LINE_1St = new EventBus("first"); static AsyncEventBus LINE_2Ed = new AsyncEventBus("second", new Executor() { @Override public void execute(Runnable command) { try { Thread.sleep(10000L); command.run(); } catch (InterruptedException e) { System.out.println(e); } } }); public static void main(String[] args) { LINE_1St.register(new EventListener()); LINE_2Ed.register(new EventListener()); int cpuNums = Runtime.getRuntime().availableProcessors(); ExecutorService executorService = Executors.newFixedThreadPool(cpuNums * 1); Thread thread1 = new Thread() { @Override public void run() { PromoEvent promoEvent = genPromoEvent(); LINE_1St.post(promoEvent); } }; Thread thread2 = new Thread() { @Override public void run() { LINE_2Ed.post(genDimensionEvent()); } }; Thread thread3 = new Thread() { @Override public void run() { try { Thread.sleep(5000); LINE_1St.post(111); } catch (InterruptedException e) { e.printStackTrace(); } } }; executorService.execute(thread1); executorService.execute(thread2); executorService.execute(thread3); } static PromoEvent genPromoEvent() { PromoEvent event = new PromoEvent(1, Lists.newArrayList(1L, 2L, 3L), System.currentTimeMillis(), 0L); return event; } static DimensionEvent genDimensionEvent() { DimensionEvent event = new DimensionEvent(100, Lists.newArrayList(100L, 200L, 300L), System.currentTimeMillis(), 0L); return event; }
然后有两个自定义事件内容,基本上内容是一样的,只是用来测试:
public class PromoEvent { private int activityId; private List<Long> productIds; private Long currentTime; private Long triedTimes; /** * @param activityId * @param productIds * @param currentTime * @param triedTimes */ public PromoEvent(int activityId, List<Long> productIds, Long currentTime, Long triedTimes) { super(); this.activityId = activityId; this.productIds = productIds; this.currentTime = currentTime; this.triedTimes = triedTimes; } public int getActivityId() { return activityId; } public void setActivityId(int activityId) { this.activityId = activityId; } public List<Long> getProductIds() { return productIds; } public void setProductIds(List<Long> productIds) { this.productIds = productIds; } public Long getCurrentTime() { return currentTime; } public void setCurrentTime(Long currentTime) { this.currentTime = currentTime; } public Long getTriedTimes() { return triedTimes; } public void setTriedTimes(Long triedTimes) { this.triedTimes = triedTimes; } @Override public String toString() { return "EventTest [activityId=" + activityId + ", productIds=" + productIds + ", currentTime=" + currentTime + ", triedTimes=" + triedTimes + "]"; }
事件监听:
public class EventListener { private PromoEvent lastPromoMessage = null; private DimensionEvent lastDimensionMessage = null; private DeadEvent deadEvent = null; @Subscribe public void listen(PromoEvent event) { lastPromoMessage = event; System.out.println("~~~~~~~~~~PromoEvent~~~~~~~~~~~~~"); System.out.println(event.toString()); } @Subscribe public void listen(DimensionEvent event) { lastDimensionMessage = event; System.out.println("----------DimensionEvent---------"); System.out.println(event.toString()); } @Subscribe public void listen(DeadEvent event) { deadEvent = event; System.out.println("===========DeadEvent============="); System.out.println(event.toString()); } public PromoEvent getLastPromoMessage() { return lastPromoMessage; } public DimensionEvent getLastDimensionMessage() { return lastDimensionMessage; } public DeadEvent getDeadEvent() { return deadEvent;
我们声明了两个Bus总线,用来分别存放消息体:
static final EventBus LINE_1St = new EventBus("first"); static AsyncEventBus LINE_2Ed = new AsyncEventBus("second", new Executor() {····});
然后声明3个线程,分别往同步总线里面放一个消息;延迟5秒往同步线程里面放一个无效消息;然后向延迟10秒的异步线程里面放一条消息;
然后监听器Listener分别处理这几个消息,下面是输出结果:
~~~~~~~~~~PromoEvent~~~~~~~~~~~~~ EventTest [activityId=1, productIds=[1, 2, 3], currentTime=1453096744555, triedTimes=0] ===========DeadEvent============= com.google.common.eventbus.DeadEvent@4ffa5d1a ----------DimensionEvent--------- EventTest [activityId=100, productIds=[100, 200, 300], currentTime=1453096744555, triedTimes=0]