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框架内部的事件处理,也为应用程序提供了一个强大的事件驱动架构基础,通过这种方式,可以实现组件间的松耦合通信,提高系统的可维护性和扩展性。整个实现考虑了性能、可靠性和易用性等多个方面,是一个非常典型的观察者模式应用案例。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/66059.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Spring Security(maven项目) 3.0.2.4版本

前言&#xff1a; 通过实践而发现真理&#xff0c;又通过实践而证实真理和发展真理。从感性认识而能动地发展到理性认识&#xff0c;又从理性认识而能动地指导革命实践&#xff0c;改造主观世界和客观世界。实践、认识、再实践、再认识&#xff0c;这种形式&#xff0c;循环往…

stm32 移植RTL8201F(正点原子例程为例)

最近在工作中需要使用RTL8201F&#xff0c;在网上找了很多帖子&#xff0c;没有找到合适的&#xff0c;自己翻资料移植了一个。 模板工程使用的是正点原子的f407探索版的例程&#xff0c;原子使用的是LAN8720,需要把他的驱动修改成为我们自己用的RTL8201F。 1.将PHY_TYPE改成我…

Unity学习笔记(四)如何实现角色攻击、组合攻击

前言 本文为Udemy课程The Ultimate Guide to Creating an RPG Game in Unity学习笔记 实现动画 首先实现角色移动的动画&#xff0c;动画的实现过程在第二篇&#xff0c;这里仅展示效果 attack1 触发攻击动画 实现脚本 接下来我们通过 Animator 编辑动画之间的过渡&#…

redis的集群模式与ELK基础

一、redis的集群模式 1.主从复制 &#xff08;1&#xff09;概述 主从模式&#xff1a;这是redis高可用的基础&#xff0c;哨兵和集群都是建立在此基础之上。 主从模式和数据库的主从模式是一样的&#xff0c;主负责写入&#xff0c;然后把写入的数据同步到从服务器&#xff…

一套比较简单的仓储系统

自己编写的一套比较简单的仓储系统&#xff0c;多仓库&#xff0c;入库、出库、明细、统计等相关功能 基于偌依的单体架构&#xff1a;springbootvueuniapp 后端&#xff1a;https://download.csdn.net/download/qq_30641447/90214834 前端&#xff1a;https://download.csdn…

网络IP协议

IP&#xff08;Internet Protocol&#xff0c;网际协议&#xff09;是TCP/IP协议族中重要的协议&#xff0c;主要负责将数据包发送给目标主机。IP相当于OSI&#xff08;图1&#xff09;的第三层网络层。网络层的主要作用是失陷终端节点之间的通信。这种终端节点之间的通信也叫点…

设计模式 创建型 原型模式(Prototype Pattern)与 常见技术框架应用 解析

原型模式&#xff08;Prototype Pattern&#xff09;是一种创建型设计模式&#xff0c;其核心思想在于通过复制现有的对象&#xff08;原型&#xff09;来创建新的对象&#xff0c;而非通过传统的构造函数或类实例化方式。这种方式在需要快速创建大量相似对象时尤为高效&#x…

MySQL(二)MySQL DDL数据库定义语言

1. MySQL DDL数据库定义语言 1.1. MySQL定义语言 进入MySQL mysql -u root -p(回车后输入密码&#xff0c;即可进入mysq1)1.1.1. 数据库操作 &#xff08;1&#xff09;查看数据库 mysql>show databases;注:MySQL语句分隔符为“&#xff1b;”   mysql库很重要它里面有…

前端页面上传文件:解决 ERR_UPLOAD_FILE_CHANGED

文章目录 引言I 问题 ERR_UPLOAD_FILE_CHANGED问题重现步骤原因II 解决方法将文件转换为base64再转回file检测文件内容是否发生变更III 知识扩展发送一个包含文件和文本的multipart/form-data请求签名优化引言 文件上传应用场景:船舶设备的新增导入(基础信息:出厂编号)船舶…

学术写作中的各种流程图如何利用Kimi进行辅助构建?

目录 1.学术论文中的流程图 2.一些小实践 3.论文中严谨的实践流程 近期小编在思考使用AI工具制作流程图和思维导图&#xff0c;结果发现Kimi现在支持流程图了&#xff0c;Kimi在学术写作中的应用变得更加广泛和深入。随着AIGC技术的不断进步&#xff0c;Kimi的功能将更加强大…

竞品分析对于ASO优化的重要性

产品要想在拥有上千万款App的App Store中脱颖而出的话&#xff0c;要有绝对优势和运营方案&#xff0c;才有可能获得用户的关注。我们要分析和自身产品相似的功能&#xff0c;了解用户获取的途径等&#xff0c;从中获取对竞品有利的因素&#xff0c;明确自身产品的增加和优化方…

什么是485专用屏蔽线

文章目录 一,485屏蔽线基本概念二,485屏蔽线结构及工作原理1、结构2、工作原理三,485屏蔽线的应用一,485屏蔽线基本概念 485屏蔽线,顾名思义,是一种应用于RS-485通信系统的屏蔽线缆。RS_485是一种常用的有线通信协议,具有长距离、高速率、低成本等优点,广泛应用于工业自…

JavaScript BOMDOM

BOM window、document、location、navigator 和 screen等&#xff0c;把它们统称为BOM&#xff08;Browser Object Model&#xff0c;浏览器对象模型&#xff09; window对象 window对象位于BOM的顶层。由浏览器创建&#xff0c;也对应JavaScript本地对象Global &#xff1…

nginx高可用集群搭建

本文介绍nginx高可用集群的搭建。利用keepalived实时检查nginx进程是否存活、keepalived的虚拟ip技术&#xff0c;达到故障转移的目的。终端用户通过访问虚拟ip&#xff0c;感知不到实际发生的故障。架构图如下&#xff1a; 0、环境 Ubuntu&#xff1a;22.04.2 ltsnginx: 1.…

【开源】创建自动签到系统—QD框架

1. 介绍 QD是一个 基于 HAR 编辑器和 Tornado 服务端的 HTTP 定时任务自动执行 Web 框架。 主要通过抓包获取到HAR来制作任务模板&#xff0c;从而实现异步响应和发起HTTP请求 2. 需要环境 2.1 硬件需求 CPU&#xff1a;至少1核 内存&#xff1a;推荐 ≥ 1G 硬盘&#xff1a;推…

【数据结构Ⅰ复习题】

如有错误欢迎指正&#xff0c;题目根据教材----------严蔚敏数据结构&#xff08;c语言版 第2版&#xff09;人民邮电电子版 数据结构Ⅰ复习题 一、填空题1&#xff0e;算法应该具备的5个重要特性有___有穷性___、确定性、可行性、输入和输出。2&#xff0e;非空单链表L中*p是头…

python爬虫--小白篇【selenium自动爬取文件】

一、问题描述 在学习或工作中需要爬取文件资源时&#xff0c;由于文件数量太多&#xff0c;手动单个下载文件效率低&#xff0c;操作麻烦&#xff0c;采用selenium框架自动爬取文件数据是不二选择。如需要爬取下面网站中包含的全部pdf文件&#xff0c;并将其转为Markdown格式。…

Edge Scdn的应用场景有哪些?

酷盾安全Edge Scdn 具备强大的安全防护能力&#xff0c;通过多层防御机制&#xff0c;如防火墙、DDoS 攻击防护、入侵检测和防御、数据加密等&#xff0c;有效抵御各种网络攻击&#xff0c;包括 DDoS 攻击、CC 攻击、SQL 注入攻击、XSS 跨站脚本攻击等&#xff0c;保障网站和应…

TCPDump参数详解及示例

TCPDump参数详解及示例 TCPDump参数详解TCPDump -G的示例TCPDump -i any -s 2048 -G 600 -p udp -Z root -n -X -tt -w %Y_%m%d_%H%M_%S.pcap &的含义TCPDump是一款强大的网络数据包截获分析工具,可以将网络中传送的数据包的完全截获下来提供分析。它支持针对网络层、协议…