Spring源码分析之事件机制——观察者模式(一)
目录
事件基类定义
事件监听器接口
事件发布者接口及实现
事件广播器实现
小小总结
Spring源码分析之事件机制——观察者模式(一)-CSDN博客
Spring源码分析之事件机制——观察者模式(二)-CSDN博客
Spring源码分析之事件机制——观察者模式(三)-CSDN博客
这两篇文章是这个篇章的后篇,感兴趣的读者可以阅读一下,从spring源码分析观察者模式
事件基类定义
public abstract class ApplicationEvent extends EventObject {// 事件发生的时间戳private final long timestamp;public ApplicationEvent(Object source) {// source表示事件源,即发布事件的对象super(source);this.timestamp = System.currentTimeMillis();}// 获取事件发生时间public final long getTimestamp() {return this.timestamp;}
}
ApplicationEvent作为所有Spring事件的基类,继承自Java的EventObject,通过记录时间戳和事件源,为事件提供了基本的元数据信息,使得事件能够携带更多的上下文信息。
事件监听器接口
@FunctionalInterface
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {/*** 处理应用事件的方法* @param event 要响应的事件*/void onApplicationEvent(E event);
}
ApplicationListener接口定义了事件监听器的标准,通过泛型约束限定了具体监听的事件类型,使得监听器能够只关注特定类型的事件,我觉得spring的这种设计既保证了类型安全,又提供了良好的扩展性。
事件发布者接口及实现
@FunctionalInterface
public interface ApplicationEventPublisher {/*** 发布事件的方法* @param event 要发布的事件*/default void publishEvent(ApplicationEvent event) {publishEvent((Object) event);}/*** 发布任意对象作为事件* @param event 要发布的事件对象*/void publishEvent(Object event);
}
public abstract class AbstractApplicationContext implements ApplicationEventPublisher {// 事件广播器private ApplicationEventMulticaster applicationEventMulticaster;// 早期事件缓存,用于存储容器未完全初始化前的事件private Set<ApplicationEvent> earlyApplicationEvents;@Overridepublic void publishEvent(Object event) {// 确保事件对象是ApplicationEvent类型ApplicationEvent applicationEvent;if (event instanceof ApplicationEvent) {applicationEvent = (ApplicationEvent) event;} else {// 将普通对象包装为PayloadApplicationEventapplicationEvent = new PayloadApplicationEvent<>(this, event);}// 如果容器还在初始化,则将事件添加到早期事件集合if (this.earlyApplicationEvents != null) {this.earlyApplicationEvents.add(applicationEvent);} else {// 通过事件广播器发布事件getApplicationEventMulticaster().multicastEvent(applicationEvent);}// 如果存在父容器,则同时发布到父容器if (this.parent != null) {this.parent.publishEvent(event);}}// 初始化事件广播器protected void initApplicationEventMulticaster() {ConfigurableListableBeanFactory beanFactory = getBeanFactory();// 如果容器中已定义了广播器,则使用已定义的if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {this.applicationEventMulticaster = beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);} else {// 否则创建一个简单的事件广播器this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);}}
}
AbstractApplicationContext实现了事件发布的核心逻辑,通过事件广播器将事件分发给所有相关的监听器,同时处理了事件的向上传播和早期事件的缓存。
事件广播器实现
public class SimpleApplicationEventMulticaster extends AbstractApplicationEventMulticaster {// 任务执行器,用于异步事件处理@Nullableprivate Executor taskExecutor;// 错误处理器@Nullableprivate ErrorHandler errorHandler;@Overridepublic void multicastEvent(ApplicationEvent event) {// 解析事件类型并广播multicastEvent(event, resolveDefaultEventType(event));}@Overridepublic void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {// 解析事件类型ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));// 获取所有匹配的监听器并执行for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {Executor executor = getTaskExecutor();if (executor != null) {// 异步执行executor.execute(() -> invokeListener(listener, event));} else {// 同步执行invokeListener(listener, event);}}}protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {ErrorHandler errorHandler = getErrorHandler();if (errorHandler != null) {try {doInvokeListener(listener, event);} catch (Throwable err) {errorHandler.handleError(err);}} else {doInvokeListener(listener, event);}}
}
SimpleApplicationEventMulticaster提供了事件广播的具体实现,支持同步和异步两种事件处理方式,并提供了错误处理机制,通过这种设计,使得事件的处理更加灵活和可靠,同时也为性能优化提供了可能。
小小总结
Spring的事件机制通过这些精心设计的组件,构建了一个完整的观察者模式实现,它不仅支持Spring框架内部的事件处理,也为应用程序提供了一个强大的事件驱动架构基础,通过这种方式,可以实现组件间的松耦合通信,提高系统的可维护性和扩展性。整个实现考虑了性能、可靠性和易用性等多个方面,是一个非常典型的观察者模式应用案例。
相关文章:

Spring源码分析之事件机制——观察者模式(一)
目录 事件基类定义 事件监听器接口 事件发布者接口及实现 事件广播器实现 小小总结 Spring源码分析之事件机制——观察者模式(一)-CSDN博客 Spring源码分析之事件机制——观察者模式(二)-CSDN博客 Spring源码分析之事件机制…...

QT实现 端口扫描暂停和继续功能 3
上篇QT给端口扫描工程增加线程2-CSDN博客 为按钮pushButton_Stop添加clicked事件,功能为暂停扫描,并在暂停后显示继续按钮,点击继续按钮之后继续扫描 1.更新UI 添加继续按钮 点击转到槽则会自动声明 2. 更新 MainWindow.h 需要新增的部分…...
SHViT模型详解
模型简介 SHViT是一种创新的 单头视觉Transformer ,旨在优化计算效率和内存使用。它的核心设计理念围绕着消除传统视觉Transformer架构中的冗余元素,特别关注宏观和微观设计层面的问题。 SHViT采用了 1616的大跨度patchify stem 和 3阶段结构 ,这种独特的设计不仅有效减少…...

QGIS Server安装部署教程
一、QGIS 安装部署 1、下载安装QGIS链接如下图,选择最新的安装包文件QGIS-OSGeo4W-3.34.14-1.msi,下载完成后运行安装。 2、安装时选择QGIS安装路径不要带空格,此处会影响QGIS Server安装运行。 3、安装过程省略,安装完成后打…...

基于 Apache Commons Pool 实现的 gRPC 连接池管理类 GrpcChannelPool 性能分析与优化
基于 Apache Commons Pool 实现的 gRPC 连接池管理类 GrpcChannelPool 性能分析与优化 1. 输出关键信息的代码示例 日志记录方法 使用以下代码记录连接池的关键信息,帮助分析连接池的状态和性能瓶颈: import org.apache.commons.pool2.impl.GenericO…...
【C语言】
目录 第一个C语言程序题目实际应用程序要求输入描述输出描述示例 程序实现三级目录 第一个C语言程序 打开VS创建项目(视图-解决方案管理器)创建源文件(后缀.c).c会按照C的语言编译代码 c #include <stdio.h> //std-标准 //…...
标题:利用Spring Boot构建JWT刷新令牌应用
标题:利用Spring Boot构建JWT刷新令牌应用 去发现同类优质开源项目:https://gitcode.com/ 一、项目介绍 在Java开发中,Spring Boot以其简洁的配置和强大的功能深受开发者喜爱。Spring Boot Refresh Token with JWT 是一个开源示例项目,它展…...

性能测试工具的原理与架构解析
🍅 点击文末小卡片,免费获取软件测试全套资料,资料在手,涨薪更快 在软件开发与运维领域,性能测试是确保系统稳定、高效运行的关键环节。性能测试工具作为实现这一目标的重要工具,通过模拟真实用户行为和负载…...

基于STM32的自动水满报警系统设计
目录 引言系统设计 硬件设计软件设计系统功能模块 水位检测模块报警模块自动控制模块控制算法 水位检测逻辑报警触发逻辑代码实现 水位检测模块报警控制模块自动控制逻辑系统调试与优化结论与展望 1. 引言 水满报警系统在家庭、农业、工业等领域广泛应用,通过实时…...

C语言 数组编程练习
1.将数组A的内容和数组B中的内容进行交换。(数组一样大) 2.创建一个整形数组,完成对数组的操作 实现函数Init()初始化数组全为0 实现print()打印数组的每个元素 实现reverse()函数完成数组元素的逆置 //2.创建一个整形数组,完…...

Windows 远程桌面连接Ubuntu操作 可以自由相互复制文件 粘贴板等
1.windows不用动,用IP和用户密码直接连 Ubuntu设置 详细参考:https://blog.csdn.net/qq_22370409/article/details/88914093 新建的用户需要加入sudo 使有权限。 效果 可以自由相互复制文件 粘贴板等。...

链表OJ题(一)
(一)轮转数组 . - 力扣(LeetCode) 题目描述:给定一个整数数组 nums,将数组中的元素向右轮转 k 个位置,其中 k 是非负数。 示例一: 方法一:暴力求解 先用一个变量存储数组中的最后…...

C/C++中new/delete与malloc/free的区别及对象管理
C/C++中new/delete与malloc/free的区别及对象管理 在C/C++编程中,动态内存管理是一个核心且复杂的话题,其中new、delete、malloc和free是四个经常用于此目的的工具。尽管它们都涉及到内存的分配和释放,但它们在处理对象时的方式和效果却大相径庭。本文将通过示例来说明这些工…...

我的nvim的init.lua配置
nvim的配置文件路径在~/.config/nvim路径下: 一、目录如下: coc-settings.json文件是配置代码片段路径的文件init.lua配置文件的启动脚本lua/config.lua 全局配置文件lua/keymaps.lua 快捷键映射键文件lua/plugins.lua 插件的安装和配置文件…...
2025第1周 | JavaScript中的正则表达式
目录 1. 正则表达式是个什么东东?1.1 怎么定义正则1.2 对象字面量方式1.3 类创建方式 2. 怎么使用2.1 实例方法2.1.1 exec方法2.1.2 test方法 2.2 字符串中的方法2.2.1 match/matchAll2.2.2 replace/replaceAll2.2.3 split2.2.4 search 3. 规则3.1 修饰符3.2 字符类…...

基于 Python Django 的西西家居全屋定制系统(源码+部署+文档)
博主介绍:✌程序员徐师兄、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ 🍅文末获取源码联系🍅 👇🏻 精彩专栏推荐订阅👇…...
【Leetcode 热题 100】74. 搜索二维矩阵
问题背景 给你一个满足下述两条属性的 m n m \times n mn 整数矩阵: 每行中的整数从左到右按非严格递增顺序排列。每行的第一个整数大于前一行的最后一个整数。 给你一个整数 t a r g e t target target,如果 t a r g e t target target 在矩阵中&…...

讯方技术入库深圳市第一批建设培育产教融合型企业
产教融合是指产业与教育的紧密结合,是现代职业教育体系的重要组成部分。通过企业与学校之间的合作,使学生在学校所学的知识和技能能够更好地满足企业和社会的实际需求,同时也为企业提供高素质的技术人才,促进产业升级和经济发展。…...

阿里云代理商热销产品推荐
在数字化浪潮的推动下,企业对于云计算的依赖日益加深。阿里云,作为中国领先的云计算服务提供商,为企业提供了丰富多样的云产品和服务。本文将聚焦于阿里云代理商热销产品推荐,探讨其如何帮助企业高效利用云资源,加速数…...

海外云服务器能用来做什么?
海外云服务器不仅服务种类繁多,而且能满足多行业的需求,方便了越来越多的企业与个人。本文将探讨海外云服务器的核心服务及其适用领域,帮助企业更好地了解这一技术资源。 云存储:安全高效的数据管理 海外云服务器为用户提供了稳定…...

Spark 之 入门讲解详细版(1)
1、简介 1.1 Spark简介 Spark是加州大学伯克利分校AMP实验室(Algorithms, Machines, and People Lab)开发通用内存并行计算框架。Spark在2013年6月进入Apache成为孵化项目,8个月后成为Apache顶级项目,速度之快足见过人之处&…...
树莓派超全系列教程文档--(62)使用rpicam-app通过网络流式传输视频
使用rpicam-app通过网络流式传输视频 使用 rpicam-app 通过网络流式传输视频UDPTCPRTSPlibavGStreamerRTPlibcamerasrc GStreamer 元素 文章来源: http://raspberry.dns8844.cn/documentation 原文网址 使用 rpicam-app 通过网络流式传输视频 本节介绍来自 rpica…...

【第二十一章 SDIO接口(SDIO)】
第二十一章 SDIO接口 目录 第二十一章 SDIO接口(SDIO) 1 SDIO 主要功能 2 SDIO 总线拓扑 3 SDIO 功能描述 3.1 SDIO 适配器 3.2 SDIOAHB 接口 4 卡功能描述 4.1 卡识别模式 4.2 卡复位 4.3 操作电压范围确认 4.4 卡识别过程 4.5 写数据块 4.6 读数据块 4.7 数据流…...
Robots.txt 文件
什么是robots.txt? robots.txt 是一个位于网站根目录下的文本文件(如:https://example.com/robots.txt),它用于指导网络爬虫(如搜索引擎的蜘蛛程序)如何抓取该网站的内容。这个文件遵循 Robots…...
全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比
目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec? IPsec VPN 5.1 IPsec传输模式(Transport Mode) 5.2 IPsec隧道模式(Tunne…...

算法笔记2
1.字符串拼接最好用StringBuilder,不用String 2.创建List<>类型的数组并创建内存 List arr[] new ArrayList[26]; Arrays.setAll(arr, i -> new ArrayList<>()); 3.去掉首尾空格...
C++.OpenGL (20/64)混合(Blending)
混合(Blending) 透明效果核心原理 #mermaid-svg-SWG0UzVfJms7Sm3e {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-SWG0UzVfJms7Sm3e .error-icon{fill:#552222;}#mermaid-svg-SWG0UzVfJms7Sm3e .error-text{fill…...
LRU 缓存机制详解与实现(Java版) + 力扣解决
📌 LRU 缓存机制详解与实现(Java版) 一、📖 问题背景 在日常开发中,我们经常会使用 缓存(Cache) 来提升性能。但由于内存有限,缓存不可能无限增长,于是需要策略决定&am…...
深入浅出Diffusion模型:从原理到实践的全方位教程
I. 引言:生成式AI的黎明 – Diffusion模型是什么? 近年来,生成式人工智能(Generative AI)领域取得了爆炸性的进展,模型能够根据简单的文本提示创作出逼真的图像、连贯的文本,乃至更多令人惊叹的…...

第一篇:Liunx环境下搭建PaddlePaddle 3.0基础环境(Liunx Centos8.5安装Python3.10+pip3.10)
第一篇:Liunx环境下搭建PaddlePaddle 3.0基础环境(Liunx Centos8.5安装Python3.10pip3.10) 一:前言二:安装编译依赖二:安装Python3.10三:安装PIP3.10四:安装Paddlepaddle基础框架4.1…...