【EventBus】事件通信框架 ( 订阅方法注册 | 检查订阅方法缓存 | 反射获取订阅类中的订阅方法 )
文章目錄
- 一、檢查訂閱方法緩存
- 二、反射獲取訂閱類中的訂閱方法
- 三、完整代碼示例
一、檢查訂閱方法緩存
注冊訂閱者時 , 只傳入一個訂閱者類對象 , 其它信息都需要通過反射獲取 ;
1. 獲取訂閱者類 : 通過反射獲取該訂閱者類中的所有訂閱方法 , 凡是訂閱方法 , 都帶有 @MySubscribe 注解 ;
// 獲取訂閱者所屬類Class<?> clazz = subscriber.getClass();2. 查看方法緩存 : 查看方法緩存中 , 是否有該訂閱者對應的 訂閱類 和 訂閱方法 信息 ;
// 獲取 Class<?> clazz 參數類型對應的 訂閱者封裝類List<MySubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);3. 沒有緩存 : METHOD_CACHE 緩存中獲取的 訂閱者封裝類 集合 , 如果該集合為空 , 則說明這是首次獲取該 訂閱者類 中的 訂閱方法 , 需要反射獲取 Class<?> subscriberClass 中的所有訂閱方法 ;
if (subscriberMethods == null) {// 說明是首次獲取 , 初始化 METHOD_CACHE 緩存// 反射獲取 Class<?> subscriberClass 中的所有訂閱方法subscriberMethods = findByReflection(subscriberClass);if (! subscriberMethods.isEmpty()) {METHOD_CACHE.put(subscriberClass, subscriberMethods);}}4. 有緩存 : METHOD_CACHE 緩存中獲取的 訂閱者封裝類 集合 , 如果該集合不為空 , 說明 則直接返回該集合 ;
if (subscriberMethods == null) {} else {// 如果當前不是第一次獲取, 則直接返回從 METHOD_CACHE 緩存中獲取的 訂閱者封裝類 集合return subscriberMethods;}部分代碼示例 :
/*** 根據訂閱方法的事件參數查找訂閱方法* @param subscriberClass 訂閱者對象的類型* @return*/private List<MySubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {// 獲取 Class<?> clazz 參數類型對應的 訂閱者封裝類List<MySubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);// 此處后期重構, 減少縮進if (subscriberMethods == null) {// 說明是首次獲取 , 初始化 METHOD_CACHE 緩存// 反射獲取 Class<?> subscriberClass 中的所有訂閱方法subscriberMethods = findByReflection(subscriberClass);if (! subscriberMethods.isEmpty()) {METHOD_CACHE.put(subscriberClass, subscriberMethods);}} else {// 如果當前不是第一次獲取, 則直接返回從 METHOD_CACHE 緩存中獲取的 訂閱者封裝類 集合return subscriberMethods;}// 該分支走不到return null;}二、反射獲取訂閱類中的訂閱方法
1. 獲取所有方法 : 先通過反射獲取訂閱類中所有方法
// 通過反射獲取所有帶 @MySubscribe 注解的方法Method[] methods = subscriberClass.getMethods();2. 獲取方法信息 : 獲取方法的修飾符 , 以及方法的參數集合 ; 之后要使用這兩個值判定方法是否是訂閱方法 ;
// 獲取方法修飾符int modifiers = method.getModifiers();// 獲取方法參數Class<?>[] params = method.getParameterTypes();3. 判定方法 : 修飾符必須是 public , 參數長度必須是 1 , 保證此前提下 , 開始驗證是否有 @MySubscribe 注解 ;
// 確保修飾符必須是 public , 參數長度必須是 1if (modifiers == Modifier.PUBLIC && params.length == 1) {4. 獲取注解 : 在修飾符是 public , 參數長度為 111 的前提下 ; 調用 Method 對象的 getAnnotation 方法 , 獲取指定 Class 類型的注解 ; 如果獲取的注解不為空 , 則該方法必然是 訂閱方法 ;
// 獲取 MySubscribe 注解MySubscribe annotation = method.getAnnotation(MySubscribe.class);5. 獲取注解屬性 : @MyThreadMode 注解只定義了一個注解屬性 , 就是 threadMode 線程模式 , 可以直接調用注解對象的 threadMode() 方法 , 獲取注解屬性 ;
// 獲取線程模式MyThreadMode threadMode = annotation.threadMode();6 . 封裝訂閱方法 : 將 訂閱方法對象 , 線程模式 , 事件參數 設置到
// 此時已經完全確定該方法是一個訂閱方法 , 直接進行封裝MySubscriberMethod subscriberMethod = new MySubscriberMethod(method, // 方法對象threadMode, // 線程模式params[0] // 事件參數);7. 返回訂閱方法 : 將 訂閱類 中的 所有 訂閱方法 打包 , 放入返回集合中 ;
// 要返回的 MySubscriberMethod 集合List<MySubscriberMethod> subscriberMethods = new ArrayList<>();// 加入到返回集合中subscriberMethods.add(subscriberMethod);部分代碼示例 :
/*** 通過反射獲取 Class<?> subscriberClass 訂閱方法* @param subscriberClass 訂閱類* @return*/private List<MySubscriberMethod> findByReflection(Class<?> subscriberClass) {// 要返回的 MySubscriberMethod 集合List<MySubscriberMethod> subscriberMethods = new ArrayList<>();// 通過反射獲取所有帶 @MySubscribe 注解的方法Method[] methods = subscriberClass.getMethods();// 遍歷所有的方法 , 查找注解for (Method method : methods) {// 獲取方法修飾符int modifiers = method.getModifiers();// 獲取方法參數Class<?>[] params = method.getParameterTypes();// 確保修飾符必須是 public , 參數長度必須是 1if (modifiers == Modifier.PUBLIC && params.length == 1) {// 獲取 MySubscribe 注解MySubscribe annotation = method.getAnnotation(MySubscribe.class);// 獲取注解不為空if (annotation != null) {// 獲取線程模式MyThreadMode threadMode = annotation.threadMode();// 此時已經完全確定該方法是一個訂閱方法 , 直接進行封裝MySubscriberMethod subscriberMethod = new MySubscriberMethod(method, // 方法對象threadMode, // 線程模式params[0] // 事件參數);// 加入到返回集合中subscriberMethods.add(subscriberMethod);}}}return subscriberMethods;}三、完整代碼示例
package com.eventbus_demo.myeventbus;import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.CopyOnWriteArrayList;public class MyEventBus {/*** 方法緩存* Key - 訂閱類類型* Value - 訂閱方法 MySubscriberMethod 的集合* 取名與 EventBus 一致*/private static final Map<Class<?>, List<MySubscriberMethod>> METHOD_CACHE = new HashMap<>();/*** 解除注冊時使用* Key - 訂閱者對象* Value - 訂閱者對象中所有的訂閱方法的事件參數類型集合** 根據該訂閱者對象 , 查找所有訂閱方法的事件參數類型 , 然后再到 METHOD_CACHE 中 ,* 根據事件參數類型 , 查找對應的 MySubscriberMethod 集合* MySubscriberMethod 中封裝 訂閱者對象 + 訂閱方法**/private final Map<Object, List<Class<?>>> typesBySubscriber;/*** Key - 訂閱者方法事件參數類型* Value - 封裝 訂閱者對象 與 訂閱方法 的 MySubscription 集合* 在構造函數中初始化* CopyOnWriteArrayList 在寫入數據時會拷貝一個副本 ,* 寫完之后 , 將引用指向新的副本 ,* 該集合的線程安全級別很高*/private final Map<Class<?>, CopyOnWriteArrayList<MySubscription>> subscriptionsByEventType;/*** 全局單例*/private static MyEventBus instance;private MyEventBus() {subscriptionsByEventType = new HashMap<>();typesBySubscriber = new HashMap<>();}public static MyEventBus getInstance() {if (instance == null) {instance = new MyEventBus();}return instance;}/*** 注冊訂閱者* @param subscriber*/public void register(Object subscriber) {// 獲取訂閱者所屬類Class<?> clazz = subscriber.getClass();// 查找訂閱方法List<MySubscriberMethod> subscriberMethods = findSubscriberMethods(clazz);// 遍歷所有訂閱方法 , 進行訂閱// 首先確保查找到的訂閱方法不為空 , 并且個數大于等于 1 個if (subscriberMethods != null && !subscriberMethods.isEmpty()) {for (MySubscriberMethod method : subscriberMethods) {// 正式進行訂閱subscribe(subscriber, method);}}}/*** 根據訂閱方法的事件參數查找訂閱方法* @param subscriberClass 訂閱者對象的類型* @return*/private List<MySubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {// 獲取 Class<?> clazz 參數類型對應的 訂閱者封裝類List<MySubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);// 此處后期重構, 減少縮進if (subscriberMethods == null) {// 說明是首次獲取 , 初始化 METHOD_CACHE 緩存// 反射獲取 Class<?> subscriberClass 中的所有訂閱方法subscriberMethods = findByReflection(subscriberClass);if (! subscriberMethods.isEmpty()) {METHOD_CACHE.put(subscriberClass, subscriberMethods);}} else {// 如果當前不是第一次獲取, 則直接返回從 METHOD_CACHE 緩存中獲取的 訂閱者封裝類 集合return subscriberMethods;}// 該分支走不到return null;}/*** 通過反射獲取 Class<?> subscriberClass 訂閱方法* @param subscriberClass 訂閱類* @return*/private List<MySubscriberMethod> findByReflection(Class<?> subscriberClass) {// 要返回的 MySubscriberMethod 集合List<MySubscriberMethod> subscriberMethods = new ArrayList<>();// 通過反射獲取所有帶 @MySubscribe 注解的方法Method[] methods = subscriberClass.getMethods();// 遍歷所有的方法 , 查找注解for (Method method : methods) {// 獲取方法修飾符int modifiers = method.getModifiers();// 獲取方法參數Class<?>[] params = method.getParameterTypes();// 確保修飾符必須是 public , 參數長度必須是 1if (modifiers == Modifier.PUBLIC && params.length == 1) {// 獲取 MySubscribe 注解MySubscribe annotation = method.getAnnotation(MySubscribe.class);// 獲取注解不為空if (annotation != null) {// 獲取線程模式MyThreadMode threadMode = annotation.threadMode();// 此時已經完全確定該方法是一個訂閱方法 , 直接進行封裝MySubscriberMethod subscriberMethod = new MySubscriberMethod(method, // 方法對象threadMode, // 線程模式params[0] // 事件參數);// 加入到返回集合中subscriberMethods.add(subscriberMethod);}}}return subscriberMethods;}}
總結
以上是生活随笔為你收集整理的【EventBus】事件通信框架 ( 订阅方法注册 | 检查订阅方法缓存 | 反射获取订阅类中的订阅方法 )的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【EventBus】事件通信框架 ( 订
- 下一篇: 【EventBus】事件通信框架 ( 订