# Reactor-EventBus **Repository Path**: klesweet/reactor-event-bus ## Basic Information - **Project Name**: Reactor-EventBus - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2023-11-15 - **Last Updated**: 2023-11-15 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README ## EventBus(自写小Demo--基于Reactor-Flux、阻塞队列所完成的EventBus总线分派) [手写 EventBus:从零到一实现自己的事件总线库_手写一个eventbus_许进进的博客-CSDN博客](https://blog.csdn.net/LucasXu01/article/details/130513860) [EventBus(一):注册、分发、注销_eventbus注销-CSDN博客](https://blog.csdn.net/ZZB_Bin/article/details/80229456#:~:text=2.5 register (this)注册 1 首先得到订阅者的Class对象,2 findSubscriberMethods找出一个SubscriberMethod的集合,也就是传进来的订阅者所有的订阅的方法,把订阅方法找出来了,并保存在集合中。 3 接下来遍历订阅者的订阅方法来完成订阅者的订阅操作。 对于SubscriberMethod(订阅方法)类中,主要就是用保存订阅方法的Method对象、线程模式、事件类型、优先级、是否是粘性事件等属性。) 发布 使用的是 EventBus,是一个基于发布者/订阅者模式的事件总线框架。 此模式使用一个通道向订阅服务器发送消息,以及一个单独的回复通道向发布服务器进行通信。 事件总线(EventBus)是对发布-订阅模式的一种实现。它是一种集中式事件处理机制,允许不同的组件之间进行彼此通信而又不需要相互依赖,达到一种解耦的目的。 #### 项目架构 EventBus: ​ 存储所有的订阅者的实例subScribers、维护一个阻塞队列eventQueue用来存放代办事件、提供一个可以通过事件寻找“订阅Subscription”的Map映射subscriptionsByEventType。 ​ 类内拥有注册方法register,接受一个订阅者的实例对象,然后完成响应组件的绑定。 ​ 类内拥有post方法,接收一个事件对象,然后入栈,在里面有一个只会运行一次的Flux,会持续的关注阻塞队列,新时间进来Flux就会处理。 ​ 类内拥有反注册方法unRegister,接收一个订阅者的实例对象,将他注销掉,表示不再订阅。 ​ 类内拥有关闭对象的方法,close(); events包: ​ 包类的内需要继承Event接口,所有类都会被EventBus类的静态代码块扫描成class类对象,然后存入subscriptionsByEventType中,绑定为一个空数组,等待”订阅Subscription“被加入其中。post处理事件的时候,根据事件寻找这个subscriptionsByEventType即可。 Subscribe注解: ​ 可以被订阅者(普通的类)标识其中的方法,然后订阅者对象被register时,EventBus会扫描标识注解的方法,读取其中的Method对象。 SubscribedMethod类:使用subscriberClass、eventType、和上面获得的method构成,表示为,某一个类型的订阅者的某一个方法订阅了一个事件类型。即(**一个订阅方法**)这样就算一个类型的不同对象,订阅同一个事件,就不需要创建冗余的 关系。而是表示为类统一管理。(未实现:所有的SubscribedMethod被维护成一个Map,key是类型,value就是由他们组成的List,这样新订阅者进来,方便管理) Subscription类: ​ 由订阅者对象和上面获得的一个方法的Method构成,表示为,具体的对象,的具体的订阅方法。被通过事件分类,维护在subscriptionsByEventType中。我们post派发事件中调用订阅者的方法,就是先通过Event找到所有订阅这个事件的Subscription,之后获取里面的SubscribedMethod,调用Method。 Subscriber类:表示为一个订阅者,它里面封装了具体真实的订阅者的对象实例,以及那个实例的全部方法。这个类被EventBus用来进行管理,特别是在进行反注册的时候通过传入订阅者的对象实例,找到里面的SubscribedMethod列表,通过SubscribedMethod找到里面的event,通过event找到Subscription,删除响应的Subscription即可。 #### 使用步骤 1、新增Event事件,只需要继承Event接口即可,写好后放入events包内,可以由组件自动扫描进来。 2、新增订阅者,创建类,事件发生后的订阅方法使用@Subscribe注解标识,注解需要填入属性,属性为本方法订阅的Event事件的class类对象。 3、因为订阅者执行的订阅方法的参数,从event事件的属性中获取,所以需要注意订阅方法的形参列表,当然也可以标识一个event参数,组件会将触发的事件封装给方法。 > 注意: > 由于本项目使用了jdk8的反射功能去获取参数,因此需要打开 JVM中保留参数名的功能: > 在IDEA中: > 打开Settings -> Build,Execution,Deployment -> Compiler -> Java Compiler > 将Additional command line parameters框中设置为-parameters #### 启动流程: ​ 一开始,EventBus类加载时,会扫描events事件包,将整个项目可能出现的事件类型全部加载一边,存放入subscriptionsByEventType这一个Map里面,事件作为key,订阅该事件的SubScription列表作为value,用于post派发任务时,快速寻找到订阅方法。 #### 注册订阅者的EventBus.register()方法 执行Rundemo方法: ​ 方法内,创建总线对象EventBus,调用register方法注册订阅者,EventBus会自动扫描订阅者类内标识了@Subscribe的订阅方法,并根据该注解的属性绑定所订阅的事件Event。 ​ 使用获得的订阅方法,和Event类型,在EventBus内组装成相应的一个subscribedMethod,代表一个订阅关系。 ​ 再把这个新建的subscribedMethod和 订阅者 实例对象组装成一个SubScription,放入到subscriptionsByEventType中该事件的list里面。 ​ 最后,组装订阅者的所有方法成一个list,同订阅者实例对象 构成一个Subscriber,放入EventBus中维护的 所有订阅者subScribers列表中,方便后面 总线进行管理、反注册、资源清理。 #### 派发事件的EventBus的post()方法 RunDemo方法模拟实际事件接收,之后将采用**EventBus的post()方法**,将事件发布: ​ 一开始,直接先将事件put入阻塞队列中。之后进行判断,本类EventBus会维护一个falg,是false时,我们表示第一次post,只有第一次post会创建线程开启flux,进入阻塞队列的读取过程。否则,说明Flux已经启动,接下来的事件只需要入队就行了。 ​ 进入派发:使用双线程进行,主线程输入(接收事件),副线程(派发执行事件)。未来可以开启线程池,让派发和执行分开,派发出去之后,丢入线程池执行---主从多线程模型。创建一个Flux的Create维护一个序列,使用while语句无限读取。因为 Reactor 的执行流程是,sink.next()跳转到subscribe,所以每事件执行都会单独按顺序执行。 ​ 具体的执行:使用subscriber方法传入消费者,消费者接收event,用event获得订阅它的全部subscription,使用这两个进入invokeSubscriber方法。逐一通过反射获得形参之后,调用里面的订阅方法 > 需要注意的是: > > 该方法采用的是非异步计算,不打算等待副线程执行完了再回到主线程,因为实际情况就是这样,事件的发生是不会等待订阅者响应完成的。 注意事项: 订阅者使用 实例对象,进行订阅,因为一个类可能创建两个对象,订阅两次。 事件使用 类对象 进行标识,因为一个事件触发的是一个动作,只能是一种类型。 #### 注销订阅者的EventBus的unregister()方法: 我们对象注册进来,扫描之后封装成了SubscribedMethod,然后放进去subscriber和subscription里面, 所以我们拿到了一个需要注销掉的订阅者,只需要删除这个订阅者后面两个对象的存储即可。 需要注意的是进来的subscriber并不是Subscriber类的对象,只是订阅者的实例对象,因此需要通过它寻找Subscriber对象。 因为Subscriber对象维护了订阅者实例,还有该订阅者的订阅方法列表List\。 这样我们就拿到了一个全部都要删掉的订阅方法列表,遍历该列表逐一调用removeSubscribedMethod。 这里进去的话,获取SubscribedMethod里面的event,然后再去subscriptionsByEventType找到subscription的list 遍历之后这个event的List\寻找到由SubscribedMethod封装的Subscription,删除即可。