当前位置: 首页 > news >正文

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属性为truefalse来控制在事件监听器抛出异常时的行为。

@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&#xff1…...

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操作终端实用的技巧跟文件目录…...

第三幕 御酒掺土,江山为祭

金牌监制,您这一刀改得极其精准,直接把整部戏的格局从“江湖恩怨”拉升到了“家国博弈”的层面!确实,如果只谈慈悲,唐三藏只是个高僧;但如果加上李世民的重托和大唐的国运,他就是一个背负着沉重…...

雪球网md5__1038参数逆向解析与Node.js复现

1. 这不是“破解”,而是对前端加密逻辑的常规逆向还原你打开雪球网任意一只股票详情页,F12 打开开发者工具,切到 Network 面板,刷新页面——很快就能在 XHR 请求里捕获到类似这样的接口:https://xueqiu.com/stock/cube…...

嘈杂工业场景下的自适应VAD与双码本声纹识别鉴权系统:基于端侧轻量化神经网络与向量量化(VQ)重构

在大型化工车间、能源集控中心以及金融极密隔离库房中,离线声纹识别是物理访问控制和身份安全核验的重要生物特征屏障。然而,在环境本底噪声高达80dB以上的恶劣工业场景下,常规的语音活动检测(VAD)会频繁误触&#xff…...

Linux服务器被挖矿木马劫持的五步应急处置指南

1. 这不是“中病毒”,是服务器被劫持成了矿机——先别慌,但必须立刻断网“服务器被黑客攻击,用来挖矿!”——这句话在运维圈里一出,比收到OOM告警还让人头皮发紧。它不像网页被挂马、数据库被拖库那样有明显业务影响&a…...

FeHelper前端助手:30+开发工具集,让你的浏览器变身效率神器

FeHelper前端助手:30开发工具集,让你的浏览器变身效率神器 【免费下载链接】FeHelper 😍FeHelper--Web前端助手(Awesome!Chrome & Firefox & MS-Edge Extension, All in one Toolbox!) 项目地址:…...

孤舟笔记 互联网常用框架篇二 Dubbo服务请求失败怎么处理?集群容错策略你用过几种

文章目录先说结论Failover:换家店试试Failfast:不行就算了Failsafe:忘了这事Failback:回头再说Forking:同时点几家Broadcast:通知所有人怎么选择回答技巧与点评加分回答面试官点评个人网站分布式系统中&…...

Godot 2D随机地图三大静默故障:黑屏、穿墙、寻路失败的根源与修复

1. 为什么刚上手Godot做2D随机地图就总卡在“生成出来是黑的”“角色穿墙”“房间连不通”这三件事上?如果你是刚从Unity或GameMaker转来Godot,或者第一次用GDScript写程序逻辑的新手,大概率已经在2D随机地图生成这个环节反复摔过跟头——不是…...

第 2 期:广告视觉提效:FastAPI+LangChain 对接豆包图片模型(附完整代码)

https://mp.weixin.qq.com/s/El8_eV3wYCW-OPungbt7ng...

【MATLAB】OFDM系统峰均比抑制算法仿真

【MATLAB】OFDM系统峰均比抑制算法仿真 摘要:OFDM(正交频分复用)技术凭借抗多径衰落、频谱利用率高、抗干扰能力强等优势,广泛应用于4G/5G移动通信、WiFi、数字广播电视等无线通信系统。但OFDM系统存在固有缺陷,多子载波叠加导致时域信号出现大幅峰值,产生较高峰值平均功…...

如何快速上手SoundMind:10分钟完成音频逻辑推理模型训练

如何快速上手SoundMind:10分钟完成音频逻辑推理模型训练 【免费下载链接】SoundMind We introduce the Audio Logical Reasoning (ALR) dataset, consisting of 6,446 text-audio annotated samples specifically designed for complex reasoning tasks. Building o…...