Spring Boot 事件驱动:构建灵活可扩展的应用
在 Spring Boot 应用中,事件发布和监听机制是一种强大的工具,它允许不同的组件之间以松耦合的方式进行通信。这种机制不仅可以提高代码的可维护性和可扩展性,还能帮助我们构建更加灵活、响应式的应用。本文将深入探讨 Spring Boot 的事件发布和监听机制,揭示其工作原理,并分享一些最佳实践。
一、观察者模式的应用
Spring Boot的事件发布与监听机制基于观察者模式(Observer Pattern
),这是一种行为设计模式,其中对象之间定义了一对多的依赖关系,当一个对象的状态发生变化时,所有依赖于它的对象都会自动得到通知并更新。具体来说,在Spring Boot中,ApplicationEvent
作为事件对象,而ApplicationListener
则充当事件监听器的角色。每当某个事件发生时,Spring容器会负责通知所有的监听器,使得它们能够根据接收到的信息执行相应的操作。
二、核心概念
- 事件(Event):事件是应用中发生的某个状态变化的信号。在 Spring Boot 中,事件通常是一个继承自 ApplicationEvent 的 Java 对象。事件可以是系统事件(例如,应用启动事件、关闭事件),也可以是自定义事件(例如,用户注册事件、订单创建事件)。
- 事件发布者(Event Publisher):事件发布者负责创建并发布事件。在 Spring Boot 中,通常通过 ApplicationEventPublisher 接口来实现事件的发布。
- 事件监听器(Event Listener):事件监听器负责监听特定的事件,并在事件发生时执行相应的处理逻辑。在 Spring Boot 中,通常通过 @EventListener 注解或者实现 ApplicationListener 接口来实现事件的监听。
三、实现方式
3.1 定义事件
import org.springframework.context.ApplicationEvent;public class MyCustomEvent extends ApplicationEvent {private String message;public MyCustomEvent(Object source, String message) {super(source);this.message = message;}public String getMessage() {return message;}
}
3.2 发布事件
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;@Service
public class MyService {@Autowiredprivate ApplicationEventPublisher publisher;public void doSomething() {//发布事件publisher.publishEvent(new MyCustomEvent(this, "触发自定义事件!"));}
}
3.3 监听事件
这可以通过两种方式实现:
- 实现ApplicationListener接口:这种方式较为传统,需要显式地实现onApplicationEvent()方法。
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;@Component
public class MyEventListener implements ApplicationListener<MyCustomEvent> {@Overridepublic void onApplicationEvent(MyCustomEvent event) {System.out.println("接收到自定义事件: " + event.getMessage());}
}
值得注意的是,对于同步监听器而言,如果希望控制不同监听器之间的执行顺序,则可以使用@Order注解指定优先级。在不同的监听器类上面加上@Order(1)、@Order(2)、@Order(3)…即可
接收到自定义事件1: 触发自定义事件!
接收到自定义事件2: 触发自定义事件!
接收到自定义事件3: 触发自定义事件!
- 使用@EventListener注解:这是更为简洁的做法,只需在目标方法上添加此注解即可。此外,还可以结合@Async注解实现异步监听,但需确保已启用异步支持(例如,在主类或配置类上添加@EnableAsync)。示例代码如下所示:
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;@Component
public class MyEventListener {@EventListener@Async //使用@Async注解,进行异步处理public void handleMyCustomEvent(MyCustomEvent event) {System.out.println("接收到自定义事件: " + event.getMessage());}
}
四、工作原理
-
事件发布:当调用 ApplicationEventPublisher.publishEvent() 方法发布事件时,Spring Boot 会根据事件的类型,将事件发送给所有注册的监听器。如果配置了异步监听,则会在另外的线程处理。
-
事件监听:Spring Boot 会在应用启动时,扫描所有带有 @EventListener 注解的方法或者实现了 ApplicationListener 接口的类,并将它们注册为事件监听器。当事件发生时,Spring Boot 会根据事件类型,调用相应的监听器的方法。监听器方法可以通过参数获取事件对象,并执行相应的处理逻辑。
五、应用场景
- 用户注册:用户注册成功后,发布用户注册事件,触发发送欢迎邮件、短信通知等操作。
- 订单创建:订单创建完成后,发布订单创建事件,触发扣减库存、发送订单通知等操作。
- 日志记录:应用发生异常时,发布异常事件,记录异常信息到日志文件或数据库中。
- 系统监控:应用启动或关闭时,发布启动或关闭事件,用于系统监控。
- 模块解耦:不同模块之间通过事件进行通信,实现模块之间的解耦。
六、高级特性
除了基本的功能外,Spring Boot还提供了其他一些高级特性来丰富事件发布与监听机制的功能性:
- 条件监听:借助SpEL表达式,我们可以为@EventListener设置条件属性,只有当满足指定条件时才会触发监听器。例如,仅当用户的名字为“张三”时才处理用户更新事件。
- 事务感知:通过@TransactionalEventListener注解,可以使监听器的行为与事务状态相关联,默认情况下是在事务提交后执行监听器逻辑。
- 多播器(Multicaster):在内部,Spring使用ApplicationEventMulticaster来管理和分发事件给多个监听器,确保每个监听器都能接收到正确的事件。
七、最佳实践
- 合理定义事件: 事件应该足够细粒度,能够准确描述应用中发生的状态变化。
- 避免过度使用事件:事件机制主要用于处理异步操作,对于同步操作,应该尽量使用直接方法调用。
- 使用事件发布者接口: 为了代码的简洁和清晰,尽量使用ApplicationEventPublisher 接口发布事件,避免手动创建事件对象。
- 避免在事件监听器中执行耗时操作:如果需要在事件监听器中执行耗时操作,应该将其放入单独的线程池中执行,或者使用 @Async 注解进行异步处理。
- 注意事件的传递:如果事件需要在不同的组件之间传递,应该考虑事件的传递效率和安全性。
- 测试: 编写单元测试或集成测试,确保事件发布和监听机制的正确性。
- 异常处理: 在事件监听器中,做好异常处理,避免影响其他业务功能,可以使用try catch 捕获异常,也可以使用@ExceptionHandler 来统一处理异常。
相关文章:
Spring Boot 事件驱动:构建灵活可扩展的应用
在 Spring Boot 应用中,事件发布和监听机制是一种强大的工具,它允许不同的组件之间以松耦合的方式进行通信。这种机制不仅可以提高代码的可维护性和可扩展性,还能帮助我们构建更加灵活、响应式的应用。本文将深入探讨 Spring Boot 的事件发布…...

IM系统设计
读多写少,一般采用写扩散成timeline来做 写扩散模式 利用last message id作为这个作为最后一个消息体 timeline和批量未读和ack 利用ZSET来维护连接的定时心跳,来续约运营商的连接不断开...

华为EC6110T-海思Hi3798MV310_安卓9.0_通刷-强刷固件包
华为EC6110T-海思Hi3798MV310_安卓9.0_通刷-强刷固件包 刷机教程说明: 适用机型:华为EC6110-T、华为EC6110-U、华为EC6110-M 破解总分为两个部分:拆机短接破解(保留IPTV)和OTT卡刷(不保留IPTV)…...

ASP.NET Blazor托管模型有哪些?
今天我们来说说Blazor的三种部署方式,如果大家还不了解Blazor,那么我先简单介绍下Blazor Blazor 是一种 .NET 前端 Web 框架,在单个编程模型中同时支持服务器端呈现和客户端交互性: ● 使用 C# 创建丰富的交互式 UI。 ● 共享使用…...
PyTorch广告点击率预测(CTR)利用深度学习提升广告效果
目录 广告点击率预测问题数据集结构广告点击率预测模型的构建1. 数据集准备2. 构建数据加载器3. 构建深度学习模型4. 训练与评估 总结 广告点击率预测(CTR,Click-Through Rate Prediction)是在线广告领域中的重要任务,它帮助广告平…...

PAT甲级-1017 Queueing at Bank
题目 题目大意 银行有k个窗口,每个窗口只能服务1个人。如果3个窗口已满,就需要等待。给出n个人到达银行的时间和服务时间,要求计算每个人的平均等待时间。如果某个人的到达时间超过17:00:00,则不被服务,等待时间也不计…...

OneData体系架构详解
阿里巴巴的 OneData 体系架构方法论,主要分为三个阶段:业务板块、规范定义 和 模型设计。每个阶段的核心目标是确保数据的高效管理、共享与分析能力。 一. 业务板块(Business Segment) 业务板块是OneData体系架构中的第一步&…...
Gin 框架入门实战系列教程
一,Gin介绍 Gin是一个 Go (Golang) 编写的轻量级 http web 框架,运行速度非常快,如果你是性能和高效的追求者,我们推荐你使用Gin框架。 Gin最擅长的就是Api接口的高并发,如果项目的规模不大,业务相对简单…...
鸿蒙harmony json转对象(2)
在ArkTS(Ark TypeScript)中,接口(interface)是用来定义一个对象的结构,它可以包含属性、方法签名,以及嵌套的类型(包括其他接口或对象类型)。因此,接口里面可…...

M-LAG与E-trunk
M-LAG和E-trunk都是用来实现跨设备链路聚合,解决单点故障的,其大部分特性相同,工作模式M-LAG更胜一筹,支持双活,而且其原理感觉像是vrrpmstp的升级版,是往增加网络可靠性去发展的;而E-trunk是基于LACP扩展实现…...
【面试常见问题】
如何自我介绍 自我介绍是面试关键部分,是面试官了解求职者的首要途径,清晰自信的介绍能提升面试官印象,对求职成功至关重要。 糟糕的自我介绍示例 求职者朱晓明虽表明自己善于交际、积极,23 年毕业且从事 java 开发,…...

Spring Boot Starter介绍
前言 大概10来年以前,当时springboot刚刚出现并没有流行,当时的Java开发者们开发Web应用主要是使用spring整合springmvc或者struts、iBatis、hibernate等开发框架来进行开发。项目里一般有许多xml文件配置,其中配置了很多项目中需要用到的Be…...
vue和reacts数据响应式的差异
Vue 的数据响应式: 原理: Vue 使用 Object.defineProperty 或 Proxy(在 Vue 3 中)来实现数据的响应式。当创建 Vue 实例时,会对 data 对象中的属性进行遍历,将其转换为响应式属性。对于 Object.definePro…...
OpenEuler学习笔记(九):安装 OpenEuler后配置和优化
安装OpenEuler后,可以从系统基础设置、网络配置、性能优化等方面进行配置和优化,以下是具体内容: 系统基础设置 更新系统:以root用户登录系统后,在终端中执行sudo yum update命令,对系统进行更新…...
npm命令与yarn命令的区别
npm与Yarn的区别详解 在软件开发中,npm和Yarn都是流行的包管理工具,它们各自拥有独特的特性和优势。以下是它们的主要区别: 1. 安装速度 npm:安装速度相对较慢,尤其是在依赖项较多的情况下。Yarn:采用并…...

python如何导出数据到excel文件
python导出数据到excel文件的方法: 1、调用Workbook()对象中的add_sheet()方法 wb xlwt.Workbook() ws wb.add_sheet(A Test Sheet) 2、通过add_sheet()方法中的write()函数将数据写入到excel中,然后使用save()函数保存excel文件 ws.write(0, 0, 1234…...
MYSQL学习笔记(五):单行函数(字符串、数学、日期时间、条件判断、信息、加密、进制转换函数)讲解
前言: 学习和使用数据库可以说是程序员必须具备能力,这里将更新关于MYSQL的使用讲解,大概应该会更新30篇,涵盖入门、进阶、高级(一些原理分析);这一篇是讲解单行函数,当然mysql函数很多哈,只有多用才能记得…...

Grafana系列之Dashboard:新增仪表板、新增变量、过滤变量、变量查询、导入仪表板、变量联动、Grafana Alert
概述 关于Prometheus和Grafana的安装,略过。 写在前面 Dashboard:仪表板,可包含多个PanelPanel:面板,Dashboard中的组件 如有写得不对的地方,烦请指出。 新增仪表板 点击右上角的 选择New dashboard…...
(java版本)基于Misty1算法的加密软件的实现-毕业设计
一、基于Misty1算法的加密软件(Java)的实现 随着计算机网络及通信技术的飞速发展,信息安全成了信息社会急需解决的最重要的问题之一,密码技术是保证信息安全的核心技术。本文用JAVA语言开发了一个基于Misty1算法的加密软件&#x…...
Spring注解篇:@RestController详解
全文目录: 开篇语前言摘要概述源码解析使用案例分享代码分析使用场景优缺点分析测试用例 应用场景案例优缺点分析核心类方法介绍测试用例测试用例分析使用场景优缺点分析测试用例 小结总结文末 开篇语 哈喽,各位小伙伴们,你们好呀,…...

ESP32读取DHT11温湿度数据
芯片:ESP32 环境:Arduino 一、安装DHT11传感器库 红框的库,别安装错了 二、代码 注意,DATA口要连接在D15上 #include "DHT.h" // 包含DHT库#define DHTPIN 15 // 定义DHT11数据引脚连接到ESP32的GPIO15 #define D…...

el-switch文字内置
el-switch文字内置 效果 vue <div style"color:#ffffff;font-size:14px;float:left;margin-bottom:5px;margin-right:5px;">自动加载</div> <el-switch v-model"value" active-color"#3E99FB" inactive-color"#DCDFE6"…...

第一篇:Agent2Agent (A2A) 协议——协作式人工智能的黎明
AI 领域的快速发展正在催生一个新时代,智能代理(agents)不再是孤立的个体,而是能够像一个数字团队一样协作。然而,当前 AI 生态系统的碎片化阻碍了这一愿景的实现,导致了“AI 巴别塔问题”——不同代理之间…...
linux 下常用变更-8
1、删除普通用户 查询用户初始UID和GIDls -l /home/ ###家目录中查看UID cat /etc/group ###此文件查看GID删除用户1.编辑文件 /etc/passwd 找到对应的行,YW343:x:0:0::/home/YW343:/bin/bash 2.将标红的位置修改为用户对应初始UID和GID: YW3…...

ios苹果系统,js 滑动屏幕、锚定无效
现象:window.addEventListener监听touch无效,划不动屏幕,但是代码逻辑都有执行到。 scrollIntoView也无效。 原因:这是因为 iOS 的触摸事件处理机制和 touch-action: none 的设置有关。ios有太多得交互动作,从而会影响…...

Redis数据倾斜问题解决
Redis 数据倾斜问题解析与解决方案 什么是 Redis 数据倾斜 Redis 数据倾斜指的是在 Redis 集群中,部分节点存储的数据量或访问量远高于其他节点,导致这些节点负载过高,影响整体性能。 数据倾斜的主要表现 部分节点内存使用率远高于其他节…...

均衡后的SNRSINR
本文主要摘自参考文献中的前两篇,相关文献中经常会出现MIMO检测后的SINR不过一直没有找到相关数学推到过程,其中文献[1]中给出了相关原理在此仅做记录。 1. 系统模型 复信道模型 n t n_t nt 根发送天线, n r n_r nr 根接收天线的 MIMO 系…...
Python 包管理器 uv 介绍
Python 包管理器 uv 全面介绍 uv 是由 Astral(热门工具 Ruff 的开发者)推出的下一代高性能 Python 包管理器和构建工具,用 Rust 编写。它旨在解决传统工具(如 pip、virtualenv、pip-tools)的性能瓶颈,同时…...

HashMap中的put方法执行流程(流程图)
1 put操作整体流程 HashMap 的 put 操作是其最核心的功能之一。在 JDK 1.8 及以后版本中,其主要逻辑封装在 putVal 这个内部方法中。整个过程大致如下: 初始判断与哈希计算: 首先,putVal 方法会检查当前的 table(也就…...

消息队列系统设计与实践全解析
文章目录 🚀 消息队列系统设计与实践全解析🔍 一、消息队列选型1.1 业务场景匹配矩阵1.2 吞吐量/延迟/可靠性权衡💡 权衡决策框架 1.3 运维复杂度评估🔧 运维成本降低策略 🏗️ 二、典型架构设计2.1 分布式事务最终一致…...