spring模块(六)spring event事件(3)广播与异步问题
发布事件和监听器之间默认是同步的;监听器则是广播形式。demo:
event:
package com.listener.demo.event;import com.listener.demo.dto.UserLogDTO;
import org.springframework.context.ApplicationEvent;public class MyLogEvent extends ApplicationEvent {public MyLogEvent(UserLogDTO log) {super(log);}public UserLogDTO getSource() {return (UserLogDTO) super.getSource();}}
producer:
@RestController
@RequestMapping("/user")
@Slf4j
public class UserController {@Resourceprivate ApplicationContext applicationContext;@MyLog(url = "/user/add",detail = "addUser")@RequestMapping("/add")public String add(UserDTO userDTO) {this.notifyEvent(userDTO);log.info("请求成功,返回");return "add success";}private void notifyEvent(UserDTO userDTO) {//触发listenerUserLogDTO userLogDTO = UserLogDTO.builder().detail("新增"+userDTO.getUserAccount()).url("/user/add").build();applicationContext.publishEvent(new MyLogEvent(userLogDTO));}@MyLog(url = "/user/update",detail = "updateUser")@RequestMapping("/update")public String update() {return "update success";}
}
监听器:
package com.listener.demo.listener;import com.listener.demo.dto.UserLogDTO;
import com.listener.demo.event.MyLogEvent;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;@Slf4j
@Component
public class MyListenerOne {@EventListenerpublic void myEventListener(MyLogEvent event) {UserLogDTO source = event.getSource();log.info("监听到:url={},detail={}",source.getUrl(),source.getDetail());//其他处理,比如存储日志}@EventListenerpublic void contextRefreshedEventListener(ContextRefreshedEvent event) {log.info("监听到内置事件ContextRefreshedEvent...");}
}
目录
一、广播
二、监听器异常
三、验证同步和异步
1、默认同步
2、异步
一、广播
对于同一个Event,我们可以定义多个Listener,多个Listener之间可以通过@Order来指定顺序,order的Value值越小,执行的优先级就越高。
下面对同一个事件加上多个监听器,copy MyListenerOne为MyListenerTwo。访问接口日志打印:
2024-07-29T09:48:14.818+08:00 INFO 46376 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port 4444 (http) with context path '/listenerDemo'
2024-07-29T09:48:14.824+08:00 INFO 46376 --- [ main] c.listener.demo.listener.MyListenerOne : 监听到内置事件ContextRefreshedEvent...
2024-07-29T09:48:14.824+08:00 INFO 46376 --- [ main] c.listener.demo.listener.MyListenerTwo : 监听到内置事件ContextRefreshedEvent...
2024-07-29T09:48:14.825+08:00 INFO 46376 --- [ main] com.listener.demo.ListenerApplication : Started ListenerApplication in 1.222 seconds (process running for 1.678)
2024-07-29T09:48:22.619+08:00 INFO 46376 --- [nio-4444-exec-1] o.a.c.c.C.[.[localhost].[/listenerDemo] : Initializing Spring DispatcherServlet 'dispatcherServlet'
2024-07-29T09:48:22.619+08:00 INFO 46376 --- [nio-4444-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet'
2024-07-29T09:48:22.620+08:00 INFO 46376 --- [nio-4444-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 0 ms
2024-07-29T09:48:22.646+08:00 INFO 46376 --- [nio-4444-exec-1] c.l.demo.controller.UserController : 请求成功,返回
2024-07-29T09:48:28.656+08:00 INFO 46376 --- [ task-1] c.listener.demo.listener.MyListenerOne : 监听到:url=/user/add,detail=新增zs
2024-07-29T09:48:28.656+08:00 INFO 46376 --- [ task-2] c.listener.demo.listener.MyListenerTwo : 监听到:url=/user/add,detail=新增zs
可以看到多个listener都监听到了,是广播的形式。
二、监听器异常
在某一个Listener加入异常代码
@EventListenerpublic void myEventListener(MyLogEvent event) throws InterruptedException {//下游业务处理//Thread.sleep(6000);int a = 1/0;UserLogDTO source = event.getSource();log.info("监听到:url={},detail={}",source.getUrl(),source.getDetail());}
接口调用也异常
对于事件监听器(EventListener)抛出异常导致接口异常,可以采取以下几种策略来解决:
1、监听器加异常处理
在事件监听器中添加try-catch块来捕获并处理可能发生的异常
@EventListener
public void handleEvent(SomeEvent event) {try {// 事件处理逻辑} catch (Exception e) {// 记录日志或者进行其他处理}
}
2、阻止异常抛出
使用@TransactionalEventListener
时,设置fallbackExecution
属性为true
或false
来控制在事件监听器抛出异常时的行为。
@TransactionalEventListener(fallbackExecution = true)
public void handleEvent(SomeEvent event) {// 事件处理逻辑
}
3、使用ApplicationEventMulticaster
的事件传播策略来控制事件监听器的异常行为。
@Autowired
private ApplicationEventMulticaster multicaster;@PostConstruct
public void setTaskExecutionListenerMulticaster() {multicaster.setErrorHandler(new ErrorHandler() {@Overridepublic void handleError(Throwable t) {// 处理异常}});
}
4、异步
使用@Async
注解来异步执行事件监听器,从而避免监听器内的异常影响主线程。
@Async
@EventListener
public void handleEvent(SomeEvent event) {// 事件处理逻辑
}
三、验证同步和异步
1、默认同步
触发event,监听器和调用处是同步执行的,调用处-->listen执行-->调用处;
package com.listener.demo.controller;import com.listener.demo.annotation.MyLog;
import com.listener.demo.dto.UserDTO;
import com.listener.demo.dto.UserLogDTO;
import com.listener.demo.event.MyLogEvent;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationContext;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
@RequestMapping("/user")
@Slf4j
public class UserController {@Resourceprivate ApplicationContext applicationContext;/*@MyLog(url = "/user/add",detail = "addUser")*/@RequestMapping("/add")public String add(UserDTO userDTO) {this.notifyEvent(userDTO);log.info("请求成功,返回");return "add success";}private void notifyEvent(UserDTO userDTO) {//触发listenerUserLogDTO userLogDTO = UserLogDTO.builder().detail("新增"+userDTO.getUserAccount()).url("/user/add").build();applicationContext.publishEvent(new MyLogEvent(userLogDTO));}@MyLog(url = "/user/update",detail = "updateUser")@RequestMapping("/update")public String update() {return "update success";}
}
package com.listener.demo.listener;import com.listener.demo.dto.UserLogDTO;
import com.listener.demo.event.MyLogEvent;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;@Slf4j
@Component
public class MyListenerOne {@EventListenerpublic void myEventListener(MyLogEvent event) throws InterruptedException {//下游业务处理Thread.sleep(6000);UserLogDTO source = event.getSource();log.info("监听到:url={},detail={}",source.getUrl(),source.getDetail());}@EventListenerpublic void contextRefreshedEventListener(ContextRefreshedEvent event) {log.info("监听到内置事件ContextRefreshedEvent...");}
}
调用接口到返回的时间很长,日志打印
2024-07-29T09:42:02.161+08:00 INFO 29800 --- [nio-4444-exec-7] c.listener.demo.listener.MyListenerOne : 监听到:url=/user/add,detail=新增zs
2024-07-29T09:42:02.161+08:00 INFO 29800 --- [nio-4444-exec-7] c.l.demo.controller.UserController : 请求成功,返回
2、异步
如果需要异步执行,需要单独加上异步代码:
package com.listener.demo;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableAsync;@EnableAsync
@SpringBootApplication
public class ListenerApplication {public static void main(String[] args) {SpringApplication.run(ListenerApplication.class, args);}
}
@EventListener@Async()public void myEventListener(MyLogEvent event) throws InterruptedException {//下游业务处理Thread.sleep(6000);UserLogDTO source = event.getSource();log.info("监听到:url={},detail={}",source.getUrl(),source.getDetail());}
再次访问打印
2024-07-29T09:45:00.049+08:00 INFO 49128 --- [nio-4444-exec-3] c.l.demo.controller.UserController : 请求成功,返回
2024-07-29T09:45:06.059+08:00 INFO 49128 --- [ task-1] c.listener.demo.listener.MyListenerOne : 监听到:url=/user/add,detail=新增zs
这时候在某一个监听器加入异常代码:
@EventListener@Async()public void myEventListener(MyLogEvent event) throws InterruptedException {//下游业务处理//Thread.sleep(6000);int a = 1/0;UserLogDTO source = event.getSource();log.info("监听到:url={},detail={}",source.getUrl(),source.getDetail());}
接口可以正常访问
日志打印这一个监听器报错
相关文章:

spring模块(六)spring event事件(3)广播与异步问题
发布事件和监听器之间默认是同步的;监听器则是广播形式。demo: event: package com.listener.demo.event;import com.listener.demo.dto.UserLogDTO; import org.springframework.context.ApplicationEvent;public class MyLogEvent extends…...

【Elasticsearch系列八】高阶使用
💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…...

【H2O2|全栈】关于CSS(4)CSS基础(四)
目录 CSS基础知识 前言 准备工作 精灵图 概念 属性 案例 浮动 基础属性 清除浮动 案例 预告和回顾 后话 CSS基础知识 前言 本系列博客将分享层叠样式表(CSS)有关的知识点。 接下来的几期内容相对比较少,主要是对前面的内容进…...

node.js+Koa框架+MySQL实现注册登录
完整视频展示:https://item.taobao.com/item.htm?ftt&id831092436619&spma21dvs.23580594.0.0.52de2c1bg9gTfM 效果展示: 一、项目介绍 本项目是基于node.jsKoamysql的注册登录的项目,主要是给才学习node.js和Koa框架的萌新才写的。 二、项目…...
矢量化操作
约定 本文中的”向量”均指一维数组/张量,”矩阵”均值二维数组/张量 前言 在ML当中,向量和矩阵非常常见。由于之前使用C语言的惯性,本人经常会从标量的角度考虑向量和矩阵的运算,也就是用for循环来完成向量或矩阵的运算。实际上,for循环的风格比python内置的操作或pytor…...

【LeetCode】每日一题 2024_9_16 公交站间的距离(模拟)
前言 每天和你一起刷 LeetCode 每日一题~ LeetCode 启动! 题目:公交站间的距离 代码与解题思路 func distanceBetweenBusStops(distance []int, start int, destination int) int {// 首先让 start > destination, 这两个谁大对结果没有影响&#…...

【Python笔记】PyCharm大模型项目环境配置
一、PyCharm创建新项目 二、更新pip版本 ...>python.exe -m pip install --upgrade pip 三、生成所需requirements配置文件 ...>pip freeze > requirements.txt 四、安装所需组件requirements.txt ...>pip install -r requirements.txt...

FPGA-Vivado-IP核-虚拟输入输出(VIO)
VIO IP核 背景介绍 Vivado中的VIO(Virtual Input/Output,虚拟输入/输出) IP核是一种用于调试和测试FPGA设计的IP核。当设计者通过JTAG接口与FPGA芯片连接时,在Vivado的Verilog代码中添加VIO IP核,就可以让设计者与FPG…...

使用knn算法对iris数据集进行分类
程序功能 使用 scikit-learn 库中的鸢尾花数据集(Iris dataset),并基于 KNN(K-Nearest Neighbors,K近邻)算法进行分类,最后评估模型的准确率。 代码 from sklearn import datasets# 加载鸢尾…...

GEE Shapefile 格式转换 GeoJSON
在地理信息系统(GIS)领域,数据格式之间的转换是一项常见的需求。例如,将 Shapefile 格式转换为 GeoJSON 格式,对于上传数据到 Google Earth Engine (GEE) 尤其有用。本文将通过一个 Python 脚本的示例,实现…...

从kaggle竞赛零基础上手CV实战(Deepfake检测)
关注B站可以观看更多实战教学视频:hallo128的个人空间 从kaggle竞赛零基础上手CV实战 从kaggle竞赛零基础上手CV实战(Deepfake检测) 目录 从kaggle竞赛零基础上手CV实战(Deepfake检测)背景介绍学习地址课程大纲课程特色…...
Linux cat命令详解使用:高效文本内容管理
cat是 Linux 中最常用的命令之一,主要用于查看文件内容、合并文件以及重定向输出。它可以一次性显示文件内容,也可以将多个文件的内容串联显示出来。 基本语法 cat [选项] [文件...]常用参数选项 -n:为输出的每一行添加行号。-b࿱…...

YOLOv9改进系列,YOLOv9颈部网络SPPELAN替换为FocalModulation
摘要 焦点调制网络(简称FocalNets),其中自注意力(SA)完全由焦点调制模块取代,用于在视觉中建模标记交互。焦点调制包括三个组件:(i)焦点情境化,通过一堆深度卷积层实现,从短到长范围编码视觉上下文,(ii)门控聚合,选择性地将上下文聚集到每个查询标记的调制器中…...

圆环加载效果
效果预览 代码实现 from PyQt5.QtCore import QSize, pyqtProperty, QTimer, Qt, QThread, pyqtSignal from PyQt5.QtGui import QColor, QPainter from PyQt5.QtWidgets import QApplication, QWidget, QHBoxLayout, QPushButton, QVBoxLayout, QLabel, QGridLayoutclass Cir…...
leetcode - 分治思想
分治 - 快排 这里快排我们统一使用 数组分三块 和 随机产生基准值的方法实现排序 数组分三块: . - 力扣(LeetCode) 整个思想即将数组按照基准值分为三个区间 , 具体实现: 三指针实现. 遍历指针 , 左区间右边界指针 , 右区间左边界指针 class Solutio…...
Java面试题·解释题·单例模式、工厂模式、代理模式部分
系列文章目录 Java面试题解释题JavaSE部分 Java面试题解释题框架部分 Java面试题解释题单例模式、工厂模式、代理模式部分 文章目录 系列文章目录前言一、设计模式1. 单例模式1.1 单例模式的定义1.2 单例模式的实现方法 2. 工厂模式2.1 工厂模式的定义2.2 工厂模式的实现方法2…...

如何编写智能合约——基于长安链的Go语言的合约开发
场景设计:文件存证系统 在数字化时代,文件存证和版本追踪变得越来越重要。设想一个场景:在一个法律事务管理系统中,用户需要提交和管理各种文件的版本记录,以确保每个文件在不同时间点的状态可以被准确追踪。文件可能经…...

【PHP代码审计】PHP基础知识
🌝博客主页:菜鸟小羊 💖专栏:Linux探索之旅 | 网络安全的神秘世界 | 专接本 | 每天学会一个渗透测试工具 php简介 php是什么? php(全称:Hypertext Preprocessor,即超文本预处理器&…...

大模型笔记03--快速体验dify
大模型笔记03--快速体验dify 介绍部署&测试部署 dify测试dify对接本地ollama大模型对接阿里云千问大模型在个人网站中嵌入dify智能客服 注意事项说明 介绍 Dify 是一款开源的大语言模型(LLM) 应用开发平台。它融合了后端即服务(Backend as Service)…...

Linux常用命令以及操作技巧
🌏个人博客主页:意疏-CSDN博客 希望文章能够给到初学的你一些启发~ 如果觉得文章对你有帮助的话,点赞 关注 收藏支持一下笔者吧~ 阅读指南: 开篇说明帮助命令常见的七个linux操作终端实用的技巧跟文件目录…...

C++实现分布式网络通信框架RPC(3)--rpc调用端
目录 一、前言 二、UserServiceRpc_Stub 三、 CallMethod方法的重写 头文件 实现 四、rpc调用端的调用 实现 五、 google::protobuf::RpcController *controller 头文件 实现 六、总结 一、前言 在前边的文章中,我们已经大致实现了rpc服务端的各项功能代…...

Zustand 状态管理库:极简而强大的解决方案
Zustand 是一个轻量级、快速和可扩展的状态管理库,特别适合 React 应用。它以简洁的 API 和高效的性能解决了 Redux 等状态管理方案中的繁琐问题。 核心优势对比 基本使用指南 1. 创建 Store // store.js import create from zustandconst useStore create((set)…...

相机Camera日志实例分析之二:相机Camx【专业模式开启直方图拍照】单帧流程日志详解
【关注我,后续持续新增专题博文,谢谢!!!】 上一篇我们讲了: 这一篇我们开始讲: 目录 一、场景操作步骤 二、日志基础关键字分级如下 三、场景日志如下: 一、场景操作步骤 操作步…...

Vue3 + Element Plus + TypeScript中el-transfer穿梭框组件使用详解及示例
使用详解 Element Plus 的 el-transfer 组件是一个强大的穿梭框组件,常用于在两个集合之间进行数据转移,如权限分配、数据选择等场景。下面我将详细介绍其用法并提供一个完整示例。 核心特性与用法 基本属性 v-model:绑定右侧列表的值&…...

大数据零基础学习day1之环境准备和大数据初步理解
学习大数据会使用到多台Linux服务器。 一、环境准备 1、VMware 基于VMware构建Linux虚拟机 是大数据从业者或者IT从业者的必备技能之一也是成本低廉的方案 所以VMware虚拟机方案是必须要学习的。 (1)设置网关 打开VMware虚拟机,点击编辑…...

家政维修平台实战20:权限设计
目录 1 获取工人信息2 搭建工人入口3 权限判断总结 目前我们已经搭建好了基础的用户体系,主要是分成几个表,用户表我们是记录用户的基础信息,包括手机、昵称、头像。而工人和员工各有各的表。那么就有一个问题,不同的角色…...

Nuxt.js 中的路由配置详解
Nuxt.js 通过其内置的路由系统简化了应用的路由配置,使得开发者可以轻松地管理页面导航和 URL 结构。路由配置主要涉及页面组件的组织、动态路由的设置以及路由元信息的配置。 自动路由生成 Nuxt.js 会根据 pages 目录下的文件结构自动生成路由配置。每个文件都会对…...
VTK如何让部分单位不可见
最近遇到一个需求,需要让一个vtkDataSet中的部分单元不可见,查阅了一些资料大概有以下几种方式 1.通过颜色映射表来进行,是最正规的做法 vtkNew<vtkLookupTable> lut; //值为0不显示,主要是最后一个参数,透明度…...

让回归模型不再被异常值“带跑偏“,MSE和Cauchy损失函数在噪声数据环境下的实战对比
在机器学习的回归分析中,损失函数的选择对模型性能具有决定性影响。均方误差(MSE)作为经典的损失函数,在处理干净数据时表现优异,但在面对包含异常值的噪声数据时,其对大误差的二次惩罚机制往往导致模型参数…...

CVE-2020-17519源码分析与漏洞复现(Flink 任意文件读取)
漏洞概览 漏洞名称:Apache Flink REST API 任意文件读取漏洞CVE编号:CVE-2020-17519CVSS评分:7.5影响版本:Apache Flink 1.11.0、1.11.1、1.11.2修复版本:≥ 1.11.3 或 ≥ 1.12.0漏洞类型:路径遍历&#x…...