文章目录
一、注册订阅方法
二、完整代码示例
一、注册订阅方法
订阅方法注册的过程就是将 订阅方法参数类型 和 订阅类 + 订阅方法 封装类 , 保存到 Map<Class<?>, CopyOnWriteArrayList<MySubscription>> subscriptionsByEventType 集合中 , 该集合的键值含义如下 :
Key - 订阅者方法事件参数类型
Value - 封装 订阅者对象 与 订阅方法 的 MySubscription 集合
同时 , 还要为 取消注册 准备数据 , 取消注册数据存放在 Map<Object, List<Class<?>>> typesBySubscriber 集合中 , 该集合的键值含义如下 :
Key - 订阅者对象
Value - 订阅者方法参数集合
1. 获取事件类型 : 获取订阅方法接收的参数类型 ;
// 获取订阅方法接收的参数类型 Class<?> eventType = subscriberMethod.getEventType();
2. 获取订阅者 : 获取 Map<Class<?>, CopyOnWriteArrayList<MySubscription>> subscriptionsByEventType 集合中 eventType 参数类型对应的 订阅者封装类 ( 封装 订阅者对象 + 订阅方法 ) 集合 ;
// 获取 eventType 参数类型对应的 订阅者封装类 ( 封装 订阅者对象 + 订阅方法 ) 集合 CopyOnWriteArrayList<MySubscription> subscriptions = subscriptionsByEventType.get(eventType);
3. 订阅者为空处理 : 如果获取的集合为空 , 说明 eventType 参数对应的订阅方法一个也没有注册过 , 这里先创建一个集合 , 放到 subscriptionsByEventType 键值对中 ;
// 如果获取的集合为空 , 说明 eventType 参数对应的订阅方法一个也没有注册过
// 如果获取的集合为空 , 说明 eventType 参数对应的订阅方法一个也没有注册过 // 这里先创建一个集合 , 放到 subscriptionsByEventType 键值对中 if (subscriptions == null) { // 创建集合 subscriptions = new CopyOnWriteArrayList<>(); // 将集合设置到 subscriptionsByEventType 键值对集合中 subscriptionsByEventType.put(eventType, subscriptions); }
4. 设置订阅者集合 : 封装 订阅者对象 + 订阅方法 对象 , 将创建的 订阅者对象 + 订阅方法 对象 添加到 CopyOnWriteArrayList 集合中 ;
// 封装 订阅者对象 + 订阅方法 对象 MySubscription subscription = new MySubscription(subscriber, subscriberMethod); // 将创建的 订阅者对象 + 订阅方法 对象 添加到 CopyOnWriteArrayList 集合中 subscriptions.add(subscription);
5. 设置取消注册数据 : Map<Object, List<Class<?>>> typesBySubscriber 集合用于取消注册时 , 通过订阅者对象 查找 该订阅者对象中所有订阅方法的 事件参数类型 集合 , 然后通过事件类型 , 就可以去 Map<Class<?>, CopyOnWriteArrayList<MySubscription>> subscriptionsByEventType 集合中查找相关数据 ;
// 为取消注册准备数据 // 设置 Map<Object, List<Class<?>>> typesBySubscriber List<Class<?>> eventTypes = typesBySubscriber.get(subscriber); if (eventTypes == null) { // 创建新的集合, 用于存放订阅方法的参数类型 eventTypes = new ArrayList<>(); // 将新的集合设置到 Map<Object, List<Class<?>>> typesBySubscriber 集合中 typesBySubscriber.put(subscriber, eventTypes); } // 将新的 订阅方法类型 放入到集合中 eventTypes.add(eventType);
部分代码示例 :
/** * 方法订阅 * 将 订阅方法参数类型 和 订阅类 + 订阅方法 封装类 , 保存到 * Map<Class<?>, CopyOnWriteArrayList<MySubscription>> subscriptionsByEventType 集合中 * Key - 订阅者方法事件参数类型 * Value - 封装 订阅者对象 与 订阅方法 的 MySubscription 集合 * * 取消注册数据准备 * 取消注册数据存放在 Map<Object, List<Class<?>>> typesBySubscriber 集合中 * Key - 订阅者对象 * Value - 订阅者方法参数集合 * * @param subscriber 订阅者对象 * @param subscriberMethod 订阅方法 */ private void subscribe(Object subscriber, MySubscriberMethod subscriberMethod) { // 获取订阅方法接收的参数类型 Class<?> eventType = subscriberMethod.getEventType(); // 获取 eventType 参数类型对应的 订阅者封装类 ( 封装 订阅者对象 + 订阅方法 ) 集合 CopyOnWriteArrayList<MySubscription> subscriptions = subscriptionsByEventType.get(eventType); // 如果获取的集合为空 , 说明 eventType 参数对应的订阅方法一个也没有注册过 // 这里先创建一个集合 , 放到 subscriptionsByEventType 键值对中 if (subscriptions == null) { // 创建集合 subscriptions = new CopyOnWriteArrayList<>(); // 将集合设置到 subscriptionsByEventType 键值对集合中 subscriptionsByEventType.put(eventType, subscriptions); } // 封装 订阅者对象 + 订阅方法 对象 MySubscription subscription = new MySubscription(subscriber, subscriberMethod); // 将创建的 订阅者对象 + 订阅方法 对象 添加到 CopyOnWriteArrayList 集合中 subscriptions.add(subscription); // 为取消注册准备数据 // 设置 Map<Object, List<Class<?>>> typesBySubscriber List<Class<?>> eventTypes = typesBySubscriber.get(subscriber); if (eventTypes == null) { // 创建新的集合, 用于存放订阅方法的参数类型 eventTypes = new ArrayList<>(); // 将新的集合设置到 Map<Object, List<Class<?>>> typesBySubscriber 集合中 typesBySubscriber.put(subscriber, eventTypes); } // 将新的 订阅方法类型 放入到集合中 eventTypes.add(eventType); }
二、完整代码示例
完整代码示例 :
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); } } } /** * 方法订阅 * 将 订阅方法参数类型 和 订阅类 + 订阅方法 封装类 , 保存到 * Map<Class<?>, CopyOnWriteArrayList<MySubscription>> subscriptionsByEventType 集合中 * Key - 订阅者方法事件参数类型 * Value - 封装 订阅者对象 与 订阅方法 的 MySubscription 集合 * * 取消注册数据准备 * 取消注册数据存放在 Map<Object, List<Class<?>>> typesBySubscriber 集合中 * Key - 订阅者对象 * Value - 订阅者方法参数集合 * * @param subscriber 订阅者对象 * @param subscriberMethod 订阅方法 */ private void subscribe(Object subscriber, MySubscriberMethod subscriberMethod) { // 获取订阅方法接收的参数类型 Class<?> eventType = subscriberMethod.getEventType(); // 获取 eventType 参数类型对应的 订阅者封装类 ( 封装 订阅者对象 + 订阅方法 ) 集合 CopyOnWriteArrayList<MySubscription> subscriptions = subscriptionsByEventType.get(eventType); // 如果获取的集合为空 , 说明 eventType 参数对应的订阅方法一个也没有注册过 // 这里先创建一个集合 , 放到 subscriptionsByEventType 键值对中 if (subscriptions == null) { // 创建集合 subscriptions = new CopyOnWriteArrayList<>(); // 将集合设置到 subscriptionsByEventType 键值对集合中 subscriptionsByEventType.put(eventType, subscriptions); } // 封装 订阅者对象 + 订阅方法 对象 MySubscription subscription = new MySubscription(subscriber, subscriberMethod); // 将创建的 订阅者对象 + 订阅方法 对象 添加到 CopyOnWriteArrayList 集合中 subscriptions.add(subscription); // 为取消注册准备数据 // 设置 Map<Object, List<Class<?>>> typesBySubscriber List<Class<?>> eventTypes = typesBySubscriber.get(subscriber); if (eventTypes == null) { // 创建新的集合, 用于存放订阅方法的参数类型 eventTypes = new ArrayList<>(); // 将新的集合设置到 Map<Object, List<Class<?>>> typesBySubscriber 集合中 typesBySubscriber.put(subscriber, eventTypes); } // 将新的 订阅方法类型 放入到集合中 eventTypes.add(eventType); } /** * 根据订阅方法的事件参数查找订阅方法 * @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 , 参数长度必须是 1 if (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; } }