当前位置: 首页 > 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操作终端实用的技巧跟文件目录…...

C++实现分布式网络通信框架RPC(3)--rpc调用端

目录 一、前言 二、UserServiceRpc_Stub 三、 CallMethod方法的重写 头文件 实现 四、rpc调用端的调用 实现 五、 google::protobuf::RpcController *controller 头文件 实现 六、总结 一、前言 在前边的文章中,我们已经大致实现了rpc服务端的各项功能代…...

AI Agent与Agentic AI:原理、应用、挑战与未来展望

文章目录 一、引言二、AI Agent与Agentic AI的兴起2.1 技术契机与生态成熟2.2 Agent的定义与特征2.3 Agent的发展历程 三、AI Agent的核心技术栈解密3.1 感知模块代码示例:使用Python和OpenCV进行图像识别 3.2 认知与决策模块代码示例:使用OpenAI GPT-3进…...

CocosCreator 之 JavaScript/TypeScript和Java的相互交互

引擎版本: 3.8.1 语言: JavaScript/TypeScript、C、Java 环境:Window 参考:Java原生反射机制 您好,我是鹤九日! 回顾 在上篇文章中:CocosCreator Android项目接入UnityAds 广告SDK。 我们简单讲…...

Java 加密常用的各种算法及其选择

在数字化时代,数据安全至关重要,Java 作为广泛应用的编程语言,提供了丰富的加密算法来保障数据的保密性、完整性和真实性。了解这些常用加密算法及其适用场景,有助于开发者在不同的业务需求中做出正确的选择。​ 一、对称加密算法…...

【python异步多线程】异步多线程爬虫代码示例

claude生成的python多线程、异步代码示例,模拟20个网页的爬取,每个网页假设要0.5-2秒完成。 代码 Python多线程爬虫教程 核心概念 多线程:允许程序同时执行多个任务,提高IO密集型任务(如网络请求)的效率…...

pikachu靶场通关笔记22-1 SQL注入05-1-insert注入(报错法)

目录 一、SQL注入 二、insert注入 三、报错型注入 四、updatexml函数 五、源码审计 六、insert渗透实战 1、渗透准备 2、获取数据库名database 3、获取表名table 4、获取列名column 5、获取字段 本系列为通过《pikachu靶场通关笔记》的SQL注入关卡(共10关&#xff0…...

精益数据分析(97/126):邮件营销与用户参与度的关键指标优化指南

精益数据分析(97/126):邮件营销与用户参与度的关键指标优化指南 在数字化营销时代,邮件列表效度、用户参与度和网站性能等指标往往决定着创业公司的增长成败。今天,我们将深入解析邮件打开率、网站可用性、页面参与时…...

企业如何增强终端安全?

在数字化转型加速的今天,企业的业务运行越来越依赖于终端设备。从员工的笔记本电脑、智能手机,到工厂里的物联网设备、智能传感器,这些终端构成了企业与外部世界连接的 “神经末梢”。然而,随着远程办公的常态化和设备接入的爆炸式…...

laravel8+vue3.0+element-plus搭建方法

创建 laravel8 项目 composer create-project --prefer-dist laravel/laravel laravel8 8.* 安装 laravel/ui composer require laravel/ui 修改 package.json 文件 "devDependencies": {"vue/compiler-sfc": "^3.0.7","axios": …...

JVM虚拟机:内存结构、垃圾回收、性能优化

1、JVM虚拟机的简介 Java 虚拟机(Java Virtual Machine 简称:JVM)是运行所有 Java 程序的抽象计算机,是 Java 语言的运行环境,实现了 Java 程序的跨平台特性。JVM 屏蔽了与具体操作系统平台相关的信息,使得 Java 程序只需生成在 JVM 上运行的目标代码(字节码),就可以…...