【EventBus】EventBus 源码解析 ( 事件发送 | postToSubscription 方法 | EventBus 线程模式处理细节 )

本文涉及的产品
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: 【EventBus】EventBus 源码解析 ( 事件发送 | postToSubscription 方法 | EventBus 线程模式处理细节 )

文章目录

一、事件发送 postSingleEventForEventType 方法

二、事件发送 postToSubscription 方法

三、事件发送 invokeSubscriber 方法





一、事件发送 postSingleEventForEventType 方法


首先 , 在同步代码块中 , 根据事件类型获取 Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType 成员变量中 , 指定 事件类型 键 Key 对应的 值 Value , 即 CopyOnWriteArrayList<Subscription> 集合 ;


每个集合元素都是 Subscription 对象 , 其中封装了 一个订阅者类 和 一个订阅方法 ;


     

synchronized (this) {
          // 根据事件类型获取 Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType 
          //  成员的值 , 即 CopyOnWriteArrayList<Subscription> 集合 
          //  每个集合元素都是 Subscription 对象 
          //  其中封装了 一个订阅者类 和 一个订阅方法 
            subscriptions = subscriptionsByEventType.get(eventClass);
        }


遍历上述集合 , 调用 postToSubscription 方法 , 进行事件传递后续操作 , 主要是执行 订阅者 中的 订阅方法 ;


             

// 调用 postToSubscription 方法 , 进行事件传递后续操作
                  //  主要是执行 订阅者 中的 订阅方法 
                    postToSubscription(subscription, event, postingState.isMainThread);



EventBus.postSingleEventForEventType 方法源码 :


public class EventBus {
    private final Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType;
    private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) {
        CopyOnWriteArrayList<Subscription> subscriptions;
        synchronized (this) {
          // 根据事件类型获取 Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType 
          //  成员的值 , 即 CopyOnWriteArrayList<Subscription> 集合 
          //  每个集合元素都是 Subscription 对象 
          //  其中封装了 一个订阅者类 和 一个订阅方法 
            subscriptions = subscriptionsByEventType.get(eventClass);
        }
        // 确保 CopyOnWriteArrayList<Subscription> 集合不为空 
        if (subscriptions != null && !subscriptions.isEmpty()) {
          // 遍历上述 CopyOnWriteArrayList<Subscription> 集合 
            for (Subscription subscription : subscriptions) {
              // 将当前的事件保存在 ThreadLocal 辅助类中 
                postingState.event = event;
                // 将当前的 订阅者 和 订阅方法 封装类 保存在 ThreadLocal 辅助类中 
                postingState.subscription = subscription;
                boolean aborted;
                try {
                  // 调用 postToSubscription 方法 , 进行事件传递后续操作
                  //  主要是执行 订阅者 中的 订阅方法 
                    postToSubscription(subscription, event, postingState.isMainThread);
                    aborted = postingState.canceled;
                } finally {
                    postingState.event = null;
                    postingState.subscription = null;
                    postingState.canceled = false;
                }
                if (aborted) {
                    break;
                }
            }
            return true;
        }
        return false;
    }
}





二、事件发送 postToSubscription 方法


从 Subscription subscription 参数中 , 获取订阅方法的线程模式 , 根据 【EventBus】Subscribe 注解分析 ( Subscribe 注解属性 | threadMode 线程模型 | POSTING | MAIN | MAIN_ORDERED | ASYNC) 博客的运行规则 , 执行线程 ;


订阅方法 的执行 , 实际上是通过反射 , 调用订阅方法 , 并传入指定类型的事件作为参数 , 完成的 ;


invokeSubscriber(subscription, event);


EventBus.postToSubscription 方法源码 :


public class EventBus {
    private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {
      // 获取该 订阅方法 的线程模式 
        switch (subscription.subscriberMethod.threadMode) {
            case POSTING:
              // 不做线程切换 , 直接在发布线程中调用 
                invokeSubscriber(subscription, event);
                break;
            case MAIN:
                if (isMainThread) {
                  // 假如在主线程中 , 直接调用 
                    invokeSubscriber(subscription, event);
                } else {
                  // 假如发布线程是子线程 , 则将事件加入队列 , 通过 Handler 切换线程执行 
                    mainThreadPoster.enqueue(subscription, event);
                }
                break;
            case MAIN_ORDERED:
                if (mainThreadPoster != null) {
                    mainThreadPoster.enqueue(subscription, event);
                } else {
                    // temporary: technically not correct as poster not decoupled from subscriber
                    invokeSubscriber(subscription, event);
                }
                break;
            case BACKGROUND:
                if (isMainThread) {
                    backgroundPoster.enqueue(subscription, event);
                } else {
                    invokeSubscriber(subscription, event);
                }
                break;
            case ASYNC:
                asyncPoster.enqueue(subscription, event);
                break;
            default:
                throw new IllegalStateException("Unknown thread mode: " + subscription.subscriberMethod.threadMode);
        }
    }
}






三、事件发送 invokeSubscriber 方法


通过反射调用订阅方法 ;


EventBus.invokeSubscriber 方法源码 :


public class EventBus {
    void invokeSubscriber(Subscription subscription, Object event) {
        try {
          // 通过反射调用 订阅方法 
            subscription.subscriberMethod.method.invoke(subscription.subscriber, event);
        } catch (InvocationTargetException e) {
            handleSubscriberException(subscription, event, e.getCause());
        } catch (IllegalAccessException e) {
            throw new IllegalStateException("Unexpected exception", e);
        }
    }
}


目录
相关文章
|
2月前
|
监控 安全 数据可视化
哪些项目适合采用BOT+EPC模式?深度解析
2分钟了解什么是BOT+EPC项目管理模式以及该模式适用于哪些类型的项目。
144 1
哪些项目适合采用BOT+EPC模式?深度解析
|
1月前
|
数据可视化 算法 数据挖掘
用傅里叶变换解码时间序列:从频域视角解析季节性模式
本文介绍了如何使用傅里叶变换和周期图分析来识别时间序列中的季节性模式,特别是在能源消耗数据中。通过Python实现傅里叶变换和周期图,可以有效提取并量化时间序列中的主要和次要频率成分,克服传统可视化分析的局限性。这对于准确捕捉时间序列中的季节性变化具有重要意义。文章以AEP能源消耗数据为例,展示了如何应用这些方法识别日、周、半年等周期模式。
89 3
用傅里叶变换解码时间序列:从频域视角解析季节性模式
|
26天前
|
Java 调度
【源码】【Java并发】【线程池】邀请您从0-1阅读ThreadPoolExecutor源码
当我们创建一个`ThreadPoolExecutor`的时候,你是否会好奇🤔,它到底发生了什么?比如:我传的拒绝策略、线程工厂是啥时候被使用的? 核心线程数是个啥?最大线程数和它又有什么关系?线程池,它是怎么调度,我们传入的线程?...不要着急,小手手点上关注、点赞、收藏。主播马上从源码的角度带你们探索神秘线程池的世界...
96 0
【源码】【Java并发】【线程池】邀请您从0-1阅读ThreadPoolExecutor源码
|
1月前
|
数据采集 Web App开发 存储
深度解析:使用 Headless 模式 ChromeDriver 进行无界面浏览器操作
本文介绍了基于无界面浏览器(如ChromeDriver)和代理IP技术的现代爬虫解决方案,以应对传统爬虫面临的反爬机制和动态加载内容等问题。通过Selenium驱动ChromeDriver,并结合亿牛云爬虫代理、自定义Cookie和User-Agent设置,实现高效的数据采集。代码示例展示了如何配置ChromeDriver、处理代理认证、添加Cookie及捕获异常,确保爬虫稳定运行。性能对比显示,Headless模式下的ChromeDriver在数据采集成功率、响应时间和反爬规避能力上显著优于传统爬虫。该方案广泛应用于电商、金融和新闻媒体等行业。
118 0
深度解析:使用 Headless 模式 ChromeDriver 进行无界面浏览器操作
|
2月前
|
CDN
阿里云CDN怎么收费?看这一篇就够了,CDN不同计费模式收费价格全解析
阿里云CDN的费用由基础费用和增值费用组成。基础费用有三种计费方式:按流量、按带宽峰值和月结95带宽峰值,默认为按流量计费,价格根据使用量阶梯递减。增值费用包括静态HTTPS请求、QUIC请求等,按实际使用量收费,不使用不收费。具体收费标准和详细规则可参考阿里云官方页面。
|
3月前
|
缓存 Java 调度
多线程编程核心:上下文切换深度解析
在现代计算机系统中,多线程编程已成为提高程序性能和响应速度的关键技术。然而,多线程编程中一个不可避免的概念就是上下文切换(Context Switching)。本文将深入探讨上下文切换的概念、原因、影响以及优化策略,帮助你在工作和学习中深入理解这一技术干货。
80 10
|
3月前
|
调度 开发者
核心概念解析:进程与线程的对比分析
在操作系统和计算机编程领域,进程和线程是两个基本而核心的概念。它们是程序执行和资源管理的基础,但它们之间存在显著的差异。本文将深入探讨进程与线程的区别,并分析它们在现代软件开发中的应用和重要性。
126 4
|
3月前
|
算法 调度 开发者
多线程编程核心:上下文切换深度解析
在多线程编程中,上下文切换是一个至关重要的概念,它直接影响到程序的性能和响应速度。本文将深入探讨上下文切换的含义、原因、影响以及如何优化,帮助你在工作和学习中更好地理解和应用多线程技术。
72 4
|
3月前
|
Java 调度 Android开发
安卓与iOS开发中的线程管理差异解析
在移动应用开发的广阔天地中,安卓和iOS两大平台各自拥有独特的魅力。如同东西方文化的差异,它们在处理多线程任务时也展现出不同的哲学。本文将带你穿梭于这两个平台之间,比较它们在线程管理上的核心理念、实现方式及性能考量,助你成为跨平台的编程高手。
|
3月前
|
缓存 安全 Java
【JavaEE】——单例模式引起的多线程安全问题:“饿汉/懒汉”模式,及解决思路和方法(面试高频)
单例模式下,“饿汉模式”,“懒汉模式”,单例模式下引起的线程安全问题,解锁思路和解决方法

热门文章

最新文章

推荐镜像

更多