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

SpringBoot下使用自定义监听事件

事件机制是Spring的一个功能,目前我们使用了SpringBoot框架,所以记录下事件机制在SpringBoot框架下的使用,同时实现异步处理。事件机制其实就是使用了观察者模式(发布-订阅模式)。

Spring的事件机制经过如下流程:

  • 1、自定义事件,继承org.springframework.context.ApplicationEvent抽象类
  • 2、定义事件监听器,实现org.springframework.context.ApplicationListener接口
  • 3、在Spring容器中发布事件

SpringBoot的实例程序

实现一个保存用户的时候,向用户提供的邮箱发送一封邮件的功能,同时采用异步处理。

自定义事件

import org.springframework.context.ApplicationEvent;public class EmailEvent extends ApplicationEvent {private static final long serialVersionUID = 3733891603598996786L;private String emailAddress;public EmailEvent(String emailAddress) {super(emailAddress);this.emailAddress = emailAddress;}public String getEmailAddress() {return emailAddress;}public void setEmailAddress(String emailAddress) {this.emailAddress = emailAddress;}
}

定义事件监听器

import java.util.concurrent.TimeUnit;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;@Component
public class EmailEventListener implements ApplicationListener<EmailEvent> {private static Logger log = LoggerFactory.getLogger(EmailEventListener.class);// 异步处理@Async@Overridepublic void onApplicationEvent(EmailEvent event) {log.info("监听到事件--邮箱地址:" + event.getEmailAddress());//模拟处理的耗时3stry {TimeUnit.SECONDS.sleep(3);} catch (InterruptedException e) {e.printStackTrace();}log.info("事件处理完成");}}

发布事件

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;@Component
public class EmailEventPublish {@Autowiredprivate ApplicationContext applicationContext;public void publishEvent(String emailAddress) {EmailEvent event = new EmailEvent(emailAddress);applicationContext.publishEvent(event);}}

调用事件

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;import com.example.demo.event.EmailEventPublish;@RestController
public class EventController {private static Logger log = LoggerFactory.getLogger(EventController.class);@Autowiredprivate EmailEventPublish emailEventPublish;@RequestMapping("/event")public void publishEvent(@RequestParam String emailAddress) {// 发布事件 -- 采用异步处理emailEventPublish.publishEvent(emailAddress);// 正常该语句先执行log.info("Controller业务处理");}
}

结果

访问如下地址

http://localhost:8080/event?emailAddress=plf@163.com

结果为

2023-08-04 21:21:14.338  INFO 6400 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring FrameworkServlet 'dispatcherServlet'
2023-08-04 21:21:14.338  INFO 6400 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : FrameworkServlet 'dispatcherServlet': initialization started
2023-08-04 21:21:14.370  INFO 6400 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : FrameworkServlet 'dispatcherServlet': initialization completed in 32 ms
2023-08-04 21:21:14.429  INFO 6400 --- [nio-8080-exec-1] .s.a.AnnotationAsyncExecutionInterceptor : No task executor bean found for async processing: no bean of type TaskExecutor and no bean named 'taskExecutor' either
2023-08-04 21:21:14.534  INFO 6400 --- [nio-8080-exec-1] c.e.demo.controller.EventController      : Controller业务处理
2023-08-04 21:21:14.535  INFO 6400 --- [cTaskExecutor-1] c.example.demo.event.EmailEventListener  : 监听到事件--邮箱地址:plf@163.com
2023-08-04 21:21:17.536  INFO 6400 --- [cTaskExecutor-1] c.example.demo.event.EmailEventListener  : 事件处理完成

上述结果可知是实现了异步处理,先打印了事件之后的程序,等时间到再执行监听程序的代码。

实现异步处理就是在监听事件执行业务代码的方法上添加@Async注解,同时在启动类上添加@EnableAsync即可。

上面的日志还提到了TaskExecutor,这是如果有自定义的线程池就会去调用,如果没有就用默认的。我们也可以自己定义一个TaskExecutor

import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.lang.Nullable;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;@EnableAsync
@Configuration
public class ThreadPool implements AsyncConfigurer {@Nullable@Override@Bean("taskExecutor")public Executor getAsyncExecutor() {ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();// 线程池创建时候初始化的线程数executor.setCorePoolSize(10);// 线程池最大的线程数,只有在缓冲队列满了之后才会申请超过核心线程数的线程executor.setMaxPoolSize(20);// 用来缓冲执行任务的队列executor.setQueueCapacity(200);// 允许线程的空闲时间60秒executor.setKeepAliveSeconds(60);// 线程池名的前缀executor.setThreadNamePrefix("taskExecutor-");// 线程池对拒绝任务的处理策略executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());executor.initialize();return executor;}@Nullable@Overridepublic AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {return null;}
}

结果

2023-08-04 21:27:36.507  INFO 7848 --- [nio-8080-exec-2] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring FrameworkServlet 'dispatcherServlet'
2023-08-04 21:27:36.507  INFO 7848 --- [nio-8080-exec-2] o.s.web.servlet.DispatcherServlet        : FrameworkServlet 'dispatcherServlet': initialization started
2023-08-04 21:27:36.537  INFO 7848 --- [nio-8080-exec-2] o.s.web.servlet.DispatcherServlet        : FrameworkServlet 'dispatcherServlet': initialization completed in 30 ms
2023-08-04 21:27:36.757  INFO 7848 --- [nio-8080-exec-2] c.e.demo.controller.EventController      : Controller业务处理
2023-08-04 21:27:36.757  INFO 7848 --- [ taskExecutor-1] c.example.demo.event.EmailEventListener  : 监听到事件--邮箱地址:plf@163.com
2023-08-04 21:27:39.757  INFO 7848 --- [ taskExecutor-1] c.example.demo.event.EmailEventListener  : 事件处理完成

可知是使用我们定义的线程池[ taskExecutor-1]

总结

Spring的事件机制是一个很实用的一个功能,在监听和异步处理相关的功能比较适合。

相关文章:

SpringBoot下使用自定义监听事件

事件机制是Spring的一个功能&#xff0c;目前我们使用了SpringBoot框架&#xff0c;所以记录下事件机制在SpringBoot框架下的使用&#xff0c;同时实现异步处理。事件机制其实就是使用了观察者模式(发布-订阅模式)。 Spring的事件机制经过如下流程&#xff1a; 1、自定义事件…...

并发编程面试题1

并发编程面试题1 一、原子性高频问题&#xff1a; 1.1 Java中如何实现线程安全? 多线程操作共享数据出现的问题。 锁&#xff1a; 悲观锁&#xff1a;synchronized&#xff0c;lock乐观锁&#xff1a;CAS 可以根据业务情况&#xff0c;选择ThreadLocal&#xff0c;让每个…...

【对于一维信号的匹配】对一个一维(时间)信号y使用自定义基B执行匹配追踪(MP)研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…...

【Oracle 数据库 SQL 语句 】积累1

Oracle 数据库 SQL 语句 1、分组之后再合计2、显示不为空的值 1、分组之后再合计 关键字&#xff1a; grouping sets &#xff08;&#xff08;分组字段1&#xff0c;分组字段2&#xff09;&#xff0c;&#xff08;&#xff09;&#xff09; select sylbdm ,count(sylbmc) a…...

Django中级指南:理解并实现Django的模型和数据库迁移

Django 是一个极其强大的 Python Web 框架&#xff0c;它提供了许多工具和特性&#xff0c;能够帮助我们更快速、更便捷地构建 Web 应用。在本文中&#xff0c;我们将会关注 Django 中的模型&#xff08;Models&#xff09;和数据库迁移&#xff08;Database Migrations&#x…...

Chatgpt API调用报错:openai.error.RateLimitError

Chatgpt API 调用报错&#xff1a; openai.error.RateLimitError: You exceeded your current quota, please check your plan and billing details. 调用OpenAI API接口 import openai import osopenai.api_key os.getenv("OPENAI_API_KEY")result openai.Chat…...

一键获取数百张免费商用人脸!AI人脸生成器来袭

随着科技的发展&#xff0c;人工智能正在渗透到生活的各个角落&#xff0c;设计行业也不例外。在网页、APP、PPT 等界面设计中&#xff0c;设计师经常需要插入真实的人脸素材&#xff0c;以增强作品的真实感和场景化。但是获取素材既不容易&#xff0c;质量和价格也难免成为设计…...

跳跃游戏 II——力扣45

文章目录 题目描述解法一 贪心题目描述 解法一 贪心 int jump(vector<int>& nums){in...

Stable Diffusion - 常用的负向提示 Embeddings 解析与 坐姿 (Sitting) 提示词

欢迎关注我的CSDN&#xff1a;https://spike.blog.csdn.net/ 本文地址&#xff1a;https://spike.blog.csdn.net/article/details/132145248 负向 Embeddings 是用于提高 StableDiffusion 生成图像质量的技术&#xff0c;可以避免生成一些不符合预期的图像特征&#xff0c;比如…...

工厂方法模式(一):C#实现指南

工厂方法模式是一种创建型设计模式&#xff0c;用于处理对象的创建问题。通过使用工厂方法模式&#xff0c;我们可以将对象的创建过程与使用过程分离&#xff0c;从而增加代码的灵活性和可维护性。 工厂方法模式的定义 工厂方法模式定义了一个创建对象的接口&#xff0c;但由子…...

Spring接口InitializingBean的作用和使用介绍

在Spring框架中&#xff0c;InitializingBean接口是一个回调接口&#xff0c;用于在Spring容器实例化Bean并设置Bean的属性之后&#xff0c;执行一些自定义的初始化逻辑。实现InitializingBean接口的Bean可以在初始化阶段进行一些必要的操作&#xff0c;比如数据的初始化、资源…...

Excel---成绩相同者,名次并列排列,三步搞定

需求&#xff1a;一张成绩表&#xff0c;共341行(340条数据&#xff0c;第一条为标题)&#xff0c;根据成绩进行排序&#xff0c;成绩相同进行名次并列 一、选择生成结果的位置&#xff0c;我这里点击了一下E2单元格 二、公式—>插入–>rank函数 数值&#xff1a;D2 表示…...

Elasticsearch6.x和7.x的区别

Elasticsearch6.x和7.x的区别 1、查找方面的区别 在增删改方面&#xff0c;6.x和7.x是一样的&#xff0c;在查找方面&#xff08;分为普通查找和有高亮的查找&#xff09;&#xff0c;6.x和7.x有区别。 在7.x的es中&#xff1a; org.springframework.data.elasticsearch.cor…...

基于STM32设计的口罩识别和无线测温系统

一、设计需求 基于STM32设计的口罩识别和无线测温系统 1.1 项目背景 随着深度学习和计算机视觉的快读发展,与此有关的技术设备已经被大幅度的使用,并且不仅仅在这两个方面,更在许许多多的领域都有使用。众所周知,图像理解之中的最重要的一个步骤即为目标检测,和为目标检测…...

第五十天

●软件测试的目的 软件测试的目的是寻找错误&#xff0c;并且尽可能找出更多的错误。 测试是程序的执行过程&#xff0c;目的在于发现错误 一个好的测试用例在于能够发现至今为止未发现的错误 一个成功的测试是发现了至今未发现的错误的测试 ●软件测试工作流程&#xff1…...

vue-pc端elementui-统一修改问题-Dialog 对话框点击空白关闭问题-element-所有组件层级问题

前言 实际开发我们经常发现dialog弹出框默认点击遮罩层空白地方就会关闭-有属性可以关闭 但是经常会图方便-或者已经写完了&#xff0c;不想一个个写&#xff0c;可以在main.js进行统一关闭 当我们在页面进行复杂设计和层级关闭改变&#xff0c;会发现右上角的退出登录弹出款…...

VS code 用户设置

ctrlshiftP打开用户设设置 vscode user setting.json 中的配置 {// vscode默认启用了根据文件类型自动设置tabsize的选项"editor.detectIndentation": false,//黄色波浪线"eslint.enable": false,// 重新设定tabsize"editor.tabSize": 2,&quo…...

【Spring security 解决跨域】

security 跨域 概述方案方案一方案二方案三方案四 主页传送门&#xff1a;&#x1f4c0; 传送 概述 Spring Security是一个功能强大且高度可定制的&#xff0c;主要负责为Java程序提供声明式的身份验证和访问控制的安全框架。其前身是Acegi Security,后来被收纳为Spring的一个…...

【C语言】经典题目(四)

HI&#xff0c;大家好~&#x1f61d;&#x1f61d;这是一篇C语言经典题目的博客。 更多C语言经典题目及刷题篇&#xff0c;可以参考&#xff1a; &#x1f338; 【C语言】经典题目(一) &#x1f338; 【C语言】经典题目(二) &#x1f338; 【C语言】经典题目(三) &#x1f338;…...

Prometheus-监控 Postgresql

一、部署 1 二进制方式部署 github 地址:https://github.com/prometheus-community/postgres_exporter 1.1 下载 可以从官方发布版本中找到多个平台的二进制安装包。 打开连接后,点击 Assets,即可看到下载列表。 本文档使用如下版本作为示例 curl -o postgres_exporte…...

后进先出(LIFO)详解

LIFO 是 Last In, First Out 的缩写&#xff0c;中文译为后进先出。这是一种数据结构的工作原则&#xff0c;类似于一摞盘子或一叠书本&#xff1a; 最后放进去的元素最先出来 -想象往筒状容器里放盘子&#xff1a; &#xff08;1&#xff09;你放进的最后一个盘子&#xff08…...

Cursor实现用excel数据填充word模版的方法

cursor主页&#xff1a;https://www.cursor.com/ 任务目标&#xff1a;把excel格式的数据里的单元格&#xff0c;按照某一个固定模版填充到word中 文章目录 注意事项逐步生成程序1. 确定格式2. 调试程序 注意事项 直接给一个excel文件和最终呈现的word文件的示例&#xff0c;…...

Golang 面试经典题:map 的 key 可以是什么类型?哪些不可以?

Golang 面试经典题&#xff1a;map 的 key 可以是什么类型&#xff1f;哪些不可以&#xff1f; 在 Golang 的面试中&#xff0c;map 类型的使用是一个常见的考点&#xff0c;其中对 key 类型的合法性 是一道常被提及的基础却很容易被忽视的问题。本文将带你深入理解 Golang 中…...

【Oracle APEX开发小技巧12】

有如下需求&#xff1a; 有一个问题反馈页面&#xff0c;要实现在apex页面展示能直观看到反馈时间超过7天未处理的数据&#xff0c;方便管理员及时处理反馈。 我的方法&#xff1a;直接将逻辑写在SQL中&#xff0c;这样可以直接在页面展示 完整代码&#xff1a; SELECTSF.FE…...

定时器任务——若依源码分析

分析util包下面的工具类schedule utils&#xff1a; ScheduleUtils 是若依中用于与 Quartz 框架交互的工具类&#xff0c;封装了定时任务的 创建、更新、暂停、删除等核心逻辑。 createScheduleJob createScheduleJob 用于将任务注册到 Quartz&#xff0c;先构建任务的 JobD…...

高等数学(下)题型笔记(八)空间解析几何与向量代数

目录 0 前言 1 向量的点乘 1.1 基本公式 1.2 例题 2 向量的叉乘 2.1 基础知识 2.2 例题 3 空间平面方程 3.1 基础知识 3.2 例题 4 空间直线方程 4.1 基础知识 4.2 例题 5 旋转曲面及其方程 5.1 基础知识 5.2 例题 6 空间曲面的法线与切平面 6.1 基础知识 6.2…...

生成 Git SSH 证书

&#x1f511; 1. ​​生成 SSH 密钥对​​ 在终端&#xff08;Windows 使用 Git Bash&#xff0c;Mac/Linux 使用 Terminal&#xff09;执行命令&#xff1a; ssh-keygen -t rsa -b 4096 -C "your_emailexample.com" ​​参数说明​​&#xff1a; -t rsa&#x…...

leetcodeSQL解题:3564. 季节性销售分析

leetcodeSQL解题&#xff1a;3564. 季节性销售分析 题目&#xff1a; 表&#xff1a;sales ---------------------- | Column Name | Type | ---------------------- | sale_id | int | | product_id | int | | sale_date | date | | quantity | int | | price | decimal | -…...

是否存在路径(FIFOBB算法)

题目描述 一个具有 n 个顶点e条边的无向图&#xff0c;该图顶点的编号依次为0到n-1且不存在顶点与自身相连的边。请使用FIFOBB算法编写程序&#xff0c;确定是否存在从顶点 source到顶点 destination的路径。 输入 第一行两个整数&#xff0c;分别表示n 和 e 的值&#xff08;1…...

大数据学习(132)-HIve数据分析

​​​​&#x1f34b;&#x1f34b;大数据学习&#x1f34b;&#x1f34b; &#x1f525;系列专栏&#xff1a; &#x1f451;哲学语录: 用力所能及&#xff0c;改变世界。 &#x1f496;如果觉得博主的文章还不错的话&#xff0c;请点赞&#x1f44d;收藏⭐️留言&#x1f4…...