java eventbus 原理_EventBus原理解析
前言
EventBus的核心思想是观察者模式 (生产/消费者编程模型) 。
通过前面的文章我们已经知道,如何使用eventBus了。我们需要先定义一个Observer(前文中的EventListener类),然后将其注册到eventBus里,通过 @Subscribe 定义消息回调函数。
那我们先看看register(Object object) 和unregister(Object object) 方法。
register (Object object) 解析
public void register(Object object) {
Multimap, EventSubscriber> methodsInListener =
finder.findAllSubscribers(object);
subscribersByTypeLock.writeLock().lock();
try {
subscribersByType.putAll(methodsInListener);
} finally {
subscribersByTypeLock.writeLock().unlock();
}
}
1
2
3
4
5
6
7
8
9
10
publicvoidregister(Objectobject){
Multimap,EventSubscriber>methodsInListener=
finder.findAllSubscribers(object);
subscribersByTypeLock.writeLock().lock();
try{
subscribersByType.putAll(methodsInListener);
}finally{
subscribersByTypeLock.writeLock().unlock();
}
}
可以看到是先通过SubscriberFindingStrategy接口里的findAllSubscribers方法获取所有标记了@ Subscribe 注解的方法,其中该接口的具体实现是AnnotatedSubscriberFinder类。放到一个guava里定义的Multimap里。然后是把获取到的methodsInListener放到一个叫subscribersByType的 guava里定义的SetMultimap里 。
public Multimap, EventSubscriber> findAllSubscribers(Object listener) {
Multimap, EventSubscriber> methodsInListener = HashMultimap.create();
Class> clazz = listener.getClass();
for (Method method : getAnnotatedMethods(clazz)) {
Class>[] parameterTypes = method.getParameterTypes();
Class> eventType = parameterTypes[0];
EventSubscriber subscriber = makeSubscriber(listener, method);
methodsInListener.put(eventType, subscriber);
}
return methodsInListener;
}
1
2
3
4
5
6
7
8
9
10
11
publicMultimap,EventSubscriber>findAllSubscribers(Objectlistener){
Multimap,EventSubscriber>methodsInListener=HashMultimap.create();
Class>clazz=listener.getClass();
for(Methodmethod:getAnnotatedMethods(clazz)){
Class>[]parameterTypes=method.getParameterTypes();
Class>eventType=parameterTypes[0];
EventSubscribersubscriber=makeSubscriber(listener,method);
methodsInListener.put(eventType,subscriber);
}
returnmethodsInListener;
}
findAllSubscribers方法里,最重要的是methodsInListener,它的结构可以简单理解为一个map,其中key是eventType,在我前文写的例子中就是com.sww.eventbus.domain.MessageEvent,其中value是subscriber,就是例子中的com.sww.eventbus.listener.EventListener#onMessageEvent。
总之,一句话就是先通过标记找到所有已经注册进来的观察者,然后存放到容器里备用。
那unregister就是从容器删除它们,
unRegister (Object object) 解析
public void unregister(Object object) {
Multimap, EventSubscriber> methodsInListener = finder.findAllSubscribers(object);
for (Entry, Collection> entry :
methodsInListener.asMap().entrySet()) {
Class> eventType = entry.getKey();
Collection eventMethodsInListener = entry.getValue();
subscribersByTypeLock.writeLock().lock();
try {
Set currentSubscribers = subscribersByType.get(eventType);
if (!currentSubscribers.containsAll(eventMethodsInListener)) {
throw new IllegalArgumentException(
"missing event subscriber for an annotated method. Is " + object + " registered?");
}
currentSubscribers.removeAll(eventMethodsInListener);
} finally {
subscribersByTypeLock.writeLock().unlock();
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
publicvoidunregister(Objectobject){
Multimap,EventSubscriber>methodsInListener=finder.findAllSubscribers(object);
for(Entry,Collection>entry:
methodsInListener.asMap().entrySet()){
Class>eventType=entry.getKey();
CollectioneventMethodsInListener=entry.getValue();
subscribersByTypeLock.writeLock().lock();
try{
SetcurrentSubscribers=subscribersByType.get(eventType);
if(!currentSubscribers.containsAll(eventMethodsInListener)){
thrownewIllegalArgumentException(
"missing event subscriber for an annotated method. Is "+object+" registered?");
}
currentSubscribers.removeAll(eventMethodsInListener);
}finally{
subscribersByTypeLock.writeLock().unlock();
}
}
}
post( Object event)解析
有了观察者,下面就是发送事件了,阅读过前文会知道是通过eventBus.post(Object event)来发送事件消息。那咱们来看看这个post方法。
public void post(Object event) {
Set> dispatchTypes = flattenHierarchy(event.getClass());
boolean dispatched = false;
for (Class> eventType : dispatchTypes) {
subscribersByTypeLock.readLock().lock();
try {
Set wrappers = subscribersByType.get(eventType);
if (!wrappers.isEmpty()) {
dispatched = true;
for (EventSubscriber wrapper : wrappers) {
enqueueEvent(event, wrapper);
}
}
} finally {
subscribersByTypeLock.readLock().unlock();
}
}
if (!dispatched && !(event instanceof DeadEvent)) {
post(new DeadEvent(this, event));
}
dispatchQueuedEvents();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
publicvoidpost(Objectevent){
Set>dispatchTypes=flattenHierarchy(event.getClass());
booleandispatched=false;
for(Class>eventType:dispatchTypes){
subscribersByTypeLock.readLock().lock();
try{
Setwrappers=subscribersByType.get(eventType);
if(!wrappers.isEmpty()){
dispatched=true;
for(EventSubscriberwrapper:wrappers){
enqueueEvent(event,wrapper);
}
}
}finally{
subscribersByTypeLock.readLock().unlock();
}
}
if(!dispatched&&!(eventinstanceofDeadEvent)){
post(newDeadEvent(this,event));
}
dispatchQueuedEvents();
}
该方法就是从之前的容器subscribersByType里获取到eventType对应的观察者,然后组装成EventWithSubscriber放到队列里。
void enqueueEvent(Object event, EventSubscriber subscriber) {
eventsToDispatch.get().offer(new EventWithSubscriber(event, subscriber));
}
1
2
3
voidenqueueEvent(Objectevent,EventSubscribersubscriber){
eventsToDispatch.get().offer(newEventWithSubscriber(event,subscriber));
}
然后就是最后的dispatchQueuedEvents(),经过一层层深入进去,可以发现wrapper.handleEvent(event),其中 handleEvent方法就是最终的关键了
public void handleEvent(Object event) throws InvocationTargetException {
checkNotNull(event);
try {
method.invoke(target, new Object[] { event });
} catch (IllegalArgumentException e) {
throw new Error("Method rejected target/argument: " + event, e);
} catch (IllegalAccessException e) {
throw new Error("Method became inaccessible: " + event, e);
} catch (InvocationTargetException e) {
if (e.getCause() instanceof Error) {
throw (Error) e.getCause();
}
throw e;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
publicvoidhandleEvent(Objectevent)throwsInvocationTargetException{
checkNotNull(event);
try{
method.invoke(target,newObject[]{event});
}catch(IllegalArgumentExceptione){
thrownewError("Method rejected target/argument: "+event,e);
}catch(IllegalAccessExceptione){
thrownewError("Method became inaccessible: "+event,e);
}catch(InvocationTargetExceptione){
if(e.getCause()instanceofError){
throw(Error)e.getCause();
}
throwe;
}
}
就是通过Java的反射机制实现。
需要说明的是,如果没有订阅者注册到要发送的event事件上,并且该event不是DeadEvent,那么它将被包装成DeadEvent中并重新发布。也就是其中这三行代码索要做的
if (!dispatched && !(event instanceof DeadEvent)) {
post(new DeadEvent(this, event));
}
1
2
3
if(!dispatched&&!(eventinstanceofDeadEvent)){
post(newDeadEvent(this,event));
}
本文系本人原创,如要转载,请注明出处!
浏览量:
141
0
java eventbus 原理_EventBus原理解析相关推荐
- java eventbus 原理_本文为 Android 开源项目实现原理解析 EventBus 部分,从源码分析 EventBus 的实现原理...
之前太忙导致 Android 开源项目实现原理解析 一度搁浅,目前一期进行中,我也完成了 EventBus 分析的初稿,大家可以稍微看看后面会继续润色下. PS:本文直接复制 Markdown,格式有 ...
- Java中高级核心知识全面解析——常用框架(SpringMVC-工作原理详解)
一.先来看一下什么是 MVC 模式 MVC 是一种设计模式. MVC 的原理图如下: 二.SpringMVC 简单介绍 SpringMVC 框架是以请求为驱动,围绕 Servlet 设计,将请求发给控 ...
- java+cache使用方法_JVM代码缓存区CodeCache原理及用法解析
一. CodeCache简介 从字面意思理解就是代码缓存区,它缓存的是JIT(Just in Time)编译器编译的代码,简言之codeCache是存放JIT生成的机器码(native code).当 ...
- java overload_Java方法重载Overload原理及使用解析
这篇文章主要介绍了Java方法重载Overload原理及使用解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 为什么要用方法重载: 对于功能类似的 ...
- java中JVM的原理【转】
一.java虚拟机的生命周期: Java虚拟机的生命周期 一个运行中的Java虚拟机有着一个清晰的任务:执行Java程序.程序开始执行时他才运行,程序结束时他就停止.你在同一台机器上运行三个程序,就会 ...
- Dubbo原理和源码解析之服务引用
github新增仓库 "dubbo-read"(点此查看),集合所有<Dubbo原理和源码解析>系列文章,后续将继续补充该系列,同时将针对Dubbo所做的功能扩展也进行 ...
- 【java】Java 动态调试技术原理及实践
1.概述 转载:Java 动态调试技术原理及实践 一.动态调试要解决的问题 断点调试是我们最常使用的调试手段,它可以获取到方法执行过程中的变量信息,并可以观察到方法的执行路径.但断点调试会在断点位置停 ...
- Spark SQL架构工作原理及流程解析
Spark SQL架构工作原理及流程解析,spark sql从shark发展而来,Shark为了实现Hive兼容,在HQL方面重用了Hive中HQL的解析.逻辑执行计划翻译.执行计划优化等逻辑. Sp ...
- Java执行引擎工作原理:方法调用
Java执行引擎工作原理:方法调用 方法调用如何实现 函数指针和指针函数 CallStub源码详解 Git链接(有HotSpot源码) 1 方法调用如何实现 计算机核心三大功能:方法调用.取指.运算 ...
最新文章
- mysql索引查询 with_mysql的select语句总结与索引使用
- web service 基础学习
- 人人都是产品经理读书笔记(四)
- redis之sorted sets类型及操作
- arraylist切割_jdk8 stream list分割 切割 分批次处理工具类
- Object.prototype的成员介绍
- go语言编程项目_一个项目需要多少种编程语言?
- 软件测试—软件测试基础知识—(五)软件测试模型
- Linux定时任务Crontab详解
- Speaker Recognition: Feature Extraction
- WDS和DHCP配置说明
- 英雄无敌王朝 服务器维护,《魔法门之英雄无敌:王朝》版本更新公告
- AI npc会做成为游戏制作人的梦吗?
- 华为员工离职心声:菊厂15年退休,感恩,让我实现了财务自由!
- 英语单词听力测试软件,英语单词发音软件
- el-table复选框全部勾选以及勾选回显
- 海螺环保上市破发:收盘市值178亿港元 由海螺创业分拆
- 科研伦理与学术规范(笔记)
- JAVA游戏 混乱大枪战
- elasticsearch下载太慢在国内, 我把包放到了云盘上,还有kibana,logstash.有需要自取,持续更新版本
热门文章
- 拉普拉斯------拉普拉斯变换
- Oracle ORA-01033: ORACLE initialization or shutdown in progress 错误解决办法Windows版(手贱强制重启电脑的后果)
- 分形维数学习个人笔记1
- win32 简易版扫雷
- 开发笔记 | Springboot整合多平台支付(微信/支付宝)
- html网页设计代码作业——家乡介绍-长治(8页) HTML+CSS+JavaScript 学生DW网页设计作业成品 html网页制作期末大作业成品_网页设计期末作业
- UBTC项目11月中旬研发披露
- 优雅炫酷的WordPress 导航主题 适合做小众化导航站 源码下载
- 成功集成个推后,点击推送直接跳入app指定页面
- day13 - 对指纹图片进行噪声消除