当前位置: 首页 > 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…...

再次革新 .NET 的构建和发布方式(三)僚

1 安装与初始化 # 全局安装 OpenSpec npm install -g fission-ai/openspeclatest # 在项目目录下初始化 cd /path/to/your-project openspec init 初始化时&#xff0c;OpenSpec 会提示你选择使用的 AI 工具&#xff08;Claude Code、Cursor、Trae、Qoder 等&#xff09;。 3 O…...

文墨共鸣GPU算力优化:StructBERT模型显存占用降低40%的部署技巧

文墨共鸣GPU算力优化&#xff1a;StructBERT模型显存占用降低40%的部署技巧 1. 项目背景与挑战 文墨共鸣是一个将深度学习算法与传统水墨美学相结合的语义相似度分析系统&#xff0c;基于阿里达摩院的StructBERT大模型。在实际部署中&#xff0c;我们发现原始模型存在明显的显…...

商场消防培训还在“纸上谈兵”?一个小程序搞定签到、考试、通知全流程

消防安全培训小程序 - 功能清单 (V1.0)一、功能清单序号页面名称核心功能设计重点01登录页微信授权登录品牌展示、一键登录按钮02首页通知弹窗待办卡片顶部弹窗、进度卡片03通知列表页历史通知已读未读状态、红点提示04课程库页课程分类与列表Tab切换、进度条05课程详情页视频/…...

科哥版fft npainting lama图像修复:5分钟快速部署,小白也能轻松去除水印

科哥版fft npainting lama图像修复&#xff1a;5分钟快速部署&#xff0c;小白也能轻松去除水印 1. 引言&#xff1a;为什么选择这款图像修复工具 在日常工作和生活中&#xff0c;我们经常遇到需要处理图片的情况&#xff1a;去除水印、删除不需要的物体、修复老照片瑕疵等。…...

Windows任务栏定制神器:7+ Taskbar Tweaker让你的桌面效率翻倍

Windows任务栏定制神器&#xff1a;7 Taskbar Tweaker让你的桌面效率翻倍 【免费下载链接】7-Taskbar-Tweaker A Windows taskbar customization tool for Windows 7, Windows 8, and Windows 10 项目地址: https://gitcode.com/gh_mirrors/7t/7-Taskbar-Tweaker 你是否…...

FreakStudio瓢

环境安装 pip install keystone-engine capstone unicorn 这3个工具用法极其简单&#xff0c;下面通过示例来演示其用法。 Keystone 示例 from keystone import * CODE b"INC ECX; ADD EDX, ECX" try:ks Ks(KS_ARCH_X86, KS_MODE_64)encoding, count ks.asm(CODE)…...

分割函数 UF_MODL_split_body 的用法代码

#include <uf_modl.h> #include <uf_obj.h> double corner_pt[3]{0,0,0}; //定位极点 char * edge_len[3]{"5","10","15"}; //大小&#xff08;x&#xff0c;y&#xff0c;z&#xff09; tag_t blk_tag; UF_MODL_create_block1(UF_N…...

为什么你的PHP网关在OT环境持续丢包?深度解析ModSecurity规则冲突、SELinux上下文与内核TCP缓冲区三重隐性故障

第一章&#xff1a;工业PHP网关的典型部署架构与OT环境约束在工业自动化&#xff08;OT&#xff09;场景中&#xff0c;PHP网关并非传统Web应用的简单延伸&#xff0c;而是承担协议转换、边缘数据聚合与安全隔离的关键中间件。其部署必须严格适配现场设备的物理连接方式、实时性…...

云PDM——制造业研发数据管理的“降维打击”与国产突围

提到最让中国人骄傲的两个产业&#xff0c;非制造业和互联网莫属。当这两者发生深度化学反应时&#xff0c;真正落地的绝不是空泛的概念&#xff0c;而是实打实的技术赋能。在这波浪潮中&#xff0c;云PDM&#xff08;产品数据管理&#xff09;绝对算得上是搅动制造业研发端的一…...

Java安全编程与静态分析实战

由于当前年份尚未到达2026年&#xff0c;且未明确具体代码功能需求&#xff0c;以下提供一份通用的Java代码质量与静态分析实战示例&#xff0c;涵盖常见代码规范、静态分析工具集成和单元测试实践。假设需求为“实现一个安全的字符串处理工具类并集成静态分析”&#xff1a;代…...