EventBus
EventBus 是事件发布与订阅模式一种实现,与传统的Java Event 模型的区别是:
监听器的管理
- 传统的 Java events: 需要写代码管理对象的监听器集合, 包括同步问题, 或者使用像 EventListenerList的工具.
- 使用 EventBus: 这些EventBus 都为你做好了
事件的派发
- 传统的 Java events:需要写代码将每个事件派发给事件监听器。
- 使用 EventBus:只需要调用EventBus.post(Object)就可以了,EventBus会将事件派发给对应的事件监听器
样例:
- 订单domain
public class Order {
private String status;
private String type;
public Order(String status, String type) { this.status = status; this.type = type; }
public String getStatus() { return status; }
public void setStatus(String status) { this.status = status; }
public String getType() { return type; }
public void setType(String type) { this.type = type; }
}
- 订单事件
public class OrderEvent {
private Order order;
public OrderEvent(Order order) { this.order = order; }
public Order getOrder() { return order; }
public void setOrder(Order order) { this.order = order; }
}
- 订单事件监听器
public class OrderEventListener {
@Subscribe
public void orderStateChange(OrderEvent orderEvent) {
Order order = orderEvent.getOrder();
System.out.println(MessageFormat.format("order status change to {0}", order.getStatus()));
}
}
- 样例:
public class Demo {
public static void main(String[] args) {
EventBus eventBus = new EventBus("order");
eventBus.register(new OrderEventListener());
Order order = new Order("paid", "tmall");
OrderEvent orderEvent = new OrderEvent(order);
eventBus.post(orderEvent);
}
}
输出:
order status change to paid
可以看到订单事件和事件监听器没有实现任何接口,仅仅是使用了@Subscribe注解表明监听事件。所有的事件监听器管理和事件的派发EventBus都为我们做好了
监听多个事件
只要在监听器增加一个方法就可以了
public class OrderEventListener {
@Subscribe
public void orderStateChange(OrderEvent orderEvent) {
Order order = orderEvent.getOrder();
System.out.println(MessageFormat.format("order status change to {0}", order.getStatus()));
}
@Subscribe
public void orderTypeChange(OrderEvent orderEvent) {
Order order = orderEvent.getOrder();
System.out.println(MessageFormat.format("order type change to {0}", order.getType()));
}
}
修改后的上述程序的输出:
order type change to tmall
order status change to paid
注册
EventBus里有一个SubscriberRegistry,当向EventBus注册监听器的时候,SubscriberRegistry会根据监听器的Class查找其带有@Subscribe注解的方法,保存到SubscriberRegistry的属性subscribers(ConcurrentMap)中
void register(Object listener) {
//查找所有的订阅者,就是根据监听器的class查找带有@Subscribe注解的方法
Multimap listenerMethods = this.findAllSubscribers(listener);
Collection eventMethodsInListener;
CopyOnWriteArraySet eventSubscribers;
for(Iterator var3 = listenerMethods.asMap().entrySet().iterator(); var3.hasNext(); eventSubscribers.addAll(eventMethodsInListener)) {
Entry entry = (Entry)var3.next();
Class eventType = (Class)entry.getKey();
eventMethodsInListener = (Collection)entry.getValue();
eventSubscribers = (CopyOnWriteArraySet)this.subscribers.get(eventType);
if(eventSubscribers == null) {
CopyOnWriteArraySet newSet = new CopyOnWriteArraySet();
//保存到ConcurrentMap中
eventSubscribers = (CopyOnWriteArraySet)MoreObjects.firstNonNull(this.subscribers.putIfAbsent(eventType, newSet), newSet);
}
}
}
派发
EventBus里有一个和Dispatcher,当向EventBus发布事件的时候,Dispatcher会将事件派发给对应的事件监听器
public void post(Object event) {
//获取对应的事件监听器
Iterator eventSubscribers = this.subscribers.getSubscribers(event);
if(eventSubscribers.hasNext()) {
this.dispatcher.dispatch(event, eventSubscribers);
} else if(!(event instanceof DeadEvent)) {
this.post(new DeadEvent(this, event));
}
}
Iterator<Subscriber> getSubscribers(Object event) {
//事件类型
ImmutableSet<Class<?>> eventTypes = flattenHierarchy(event.getClass());
List<Iterator<Subscriber>> subscriberIterators =
Lists.newArrayListWithCapacity(eventTypes.size());
for (Class<?> eventType : eventTypes) {
//获取事件监听器
CopyOnWriteArraySet<Subscriber> eventSubscribers = subscribers.get(eventType);
if (eventSubscribers != null) {
// eager no-copy snapshot
subscriberIterators.add(eventSubscribers.iterator());
}
}
事件派发
void dispatch(Object event, Iterator<Subscriber> subscribers) {
checkNotNull(event);
checkNotNull(subscribers);
Queue<Event> queueForThread = queue.get();
queueForThread.offer(new Event(event, subscribers));
if (!dispatching.get()) {
dispatching.set(true);
try {
Event nextEvent;
while ((nextEvent = queueForThread.poll()) != null) {
while (nextEvent.subscribers.hasNext()) {
nextEvent.subscribers.next().dispatchEvent(nextEvent.event);
}
}
} finally {
dispatching.remove();
queue.remove();
}
}
}