【SpringBoot3】Spring Boot Event 自定义事件的发布与监听

news/2024/4/21 12:49:22/文章来源:https://blog.csdn.net/wlddhj/article/details/136466064

一、基本概况

1、什么是SpringBoot自定义事件

Spring Boot自定义事件是Spring框架中事件处理机制的一种扩展,它允许开发者在Spring Boot应用程序中定义、发布和监听自己的事件。这些事件可以用于在应用程序的不同组件之间进行通信,实现解耦和异步处理。通过自定义事件,开发者可以更加灵活地处理业务逻辑,提高系统的可扩展性和可维护性。

自定义事件通常继承自Spring的ApplicationEvent类,并包含与事件相关的数据。开发者可以定义事件监听器来监听这些事件,并在事件发生时执行相应的逻辑。事件监听器可以通过实现ApplicationListener接口或使用@EventListener注解来创建。当事件被发布时,Spring容器会负责调用所有注册了对该事件感兴趣的监听器。

因此,Spring Boot自定义事件提供了一种强大的机制,允许开发者在不直接依赖其他组件的情况下进行通信和协作,从而实现更加松耦合和可扩展的系统设计。

2、SpringBoot自定义事件是主要作用

Spring Boot自定义事件在软件开发中起着非常重要的作用,主要体现在以下几个方面:

  1. 解耦:自定义事件允许应用程序的不同部分在不需要直接相互了解的情况下进行通信。这有助于降低模块间的耦合度,使得代码更加清晰、可维护,并方便扩展。

  2. 异步处理:通过事件机制,可以将某些操作异步化,提高系统的响应性能。例如,在用户注册成功后发送欢迎邮件或短信,这些操作可以通过事件监听器异步执行,不会阻塞主线程。

  3. 业务逻辑灵活性:自定义事件提供了一种灵活的方式来处理业务逻辑。通过定义不同的事件和监听器,可以轻松地添加、修改或删除业务逻辑,而无需修改与之无关的代码。

  4. 系统通知:当系统中发生重要事件时,可以使用自定义事件来通知其他部分。例如,当数据库中的某个表发生更改时,可以发布一个事件来通知其他服务或组件进行相应的处理。

  5. 可扩展性:由于自定义事件的解耦特性,它们使得系统更加容易扩展。新的功能或模块可以通过监听特定的事件来集成到现有系统中,而无需对现有代码进行大量修改。

  6. 日志记录和审计:自定义事件也可用于记录系统中发生的重要操作或事件,以便进行日志记录和审计。这对于系统的安全性和可追溯性非常重要。

  7. 状态管理:在某些场景下,自定义事件可用于管理系统的状态。例如,当某个长时间运行的任务完成时,可以发布一个事件来更新系统的状态或触发其他相关操作。

3、SpringBoot自定义事件相关核心类

在Spring Boot中,自定义事件处理涉及的核心类主要包括以下几个:

  1. ApplicationEvent:这是所有Spring事件类的基类。自定义事件需要继承这个类,并可以在其中添加自己的属性和方法。

  2. ApplicationEventPublisher:事件发布者接口,提供了publishEvent方法来发布事件。通常你会注入这个接口的实例来发布自定义事件。

  3. ApplicationListener:事件监听器接口,需要实现这个接口并提供要监听的事件类型。当指定类型的事件被发布时,监听器的onApplicationEvent方法会被调用。

  4. EventListener:这是一个注解,用于简化事件监听器的创建。你可以将这个注解添加到任何方法上,使其成为指定类型事件的监听器。

  5. ConfigurableApplicationContext:这是Spring应用上下文的接口,它扩展了ApplicationContext接口并添加了生命周期管理和其他功能。ApplicationEventPublisher通常是通过这个接口的实现类(如AnnotationConfigApplicationContext)来获取的。

  6. TransactionalEventListener:事务事件监听,可监听事务提交前、提交后、事务回滚、事务完成(成功或失败)

在实际开发中,你通常不会直接使用ConfigurableApplicationContext,而是通过注入ApplicationEventPublisher来发布事件,并通过实现ApplicationListener接口或使用@EventListener注解来创建事件监听器。这些核心类提供了构建自定义事件处理机制所需的基本构建块。

此外,还有一些与事件处理相关的支持类,如EventListenerMethodProcessor,它是Spring内部用于处理@EventListener注解的方法的类。但通常情况下,你不需要直接与这些内部类打交道。

二、使用步骤

在Spring Boot中,自定义事件的发布与监听主要依赖于Spring Framework的事件发布-订阅机制。以下是创建、发布和监听自定义事件的基本步骤:

1. 定义自定义事件

首先,你需要定义一个继承自ApplicationEvent的自定义事件类。这个类可以包含任何你希望在事件触发时传递的数据。

import org.springframework.context.ApplicationEvent;public class CustomEvent extends ApplicationEvent {private String message;public CustomEvent(Object source, String message) {super(source);this.message = message;}public String getMessage() {return message;}
}

2. 发布自定义事件

要发布事件,你需要获取ApplicationEventPublisher的实例,然后调用它的publishEvent方法。这通常在Spring管理的Bean中完成。

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Component;@Component
public class EventPublisher {@Autowiredprivate ApplicationEventPublisher applicationEventPublisher;public void doStuffAndPublishAnEvent(final String message) {System.out.println("Publishing custom event. ");CustomEvent customEvent = new CustomEvent(this, message);applicationEventPublisher.publishEvent(customEvent);}
}

3. 监听自定义事件

要监听事件,你需要创建一个实现ApplicationListener接口的类,并指定要监听的事件类型。你也可以使用@EventListener注解来简化监听器的创建。

使用ApplicationListener接口:

import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;@Component
public class CustomEventListener implements ApplicationListener<CustomEvent> {@Overridepublic void onApplicationEvent(CustomEvent event) {System.out.println("Received custom event - " + event.getMessage());}
}

或者使用@EventListener注解:

import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;@Component
public class CustomEventListener {@EventListenerpublic void handleCustomEvent(CustomEvent event) {System.out.println("Received custom event - " + event.getMessage());}
}

4. 触发事件发布

最后,你需要在某个地方触发事件发布。这通常是通过调用上面创建的EventPublisher类的doStuffAndPublishAnEvent方法来完成的。

@Autowired
private EventPublisher eventPublisher;public void sendEvent() {eventPublisher.doStuffAndPublishAnEvent("Hello, world!");
}

这就是在Spring Boot 3中创建、发布和监听自定义事件的基本流程。注意,虽然Spring Boot 3可能在某些细节上与之前的版本有所不同,但事件处理的核心机制自Spring Framework的早期版本以来一直相对稳定。确保你正在查看与你正在使用的Spring Boot版本相对应的文档和示例。

三、使用代码示例

示例1:不定义事件,直接发布Object对象,同步

1)定义发送事件对象

public class UserEntity {private long id;private String name;private String msg;
}

2)定义事件监听器

可以添加条件condition,限制监听具体的事件


@Slf4j
@Component
public class RegisterListener {@EventListener(condition = "#entity.id != null and #entity.async==false ")public void handlerEvent(UserEntity entity) {try {// 休眠5秒TimeUnit.SECONDS.sleep(5);} catch (InterruptedException e) {e.printStackTrace();}log.info("handlerEvent: {}", entity);}}

3)定义发送接口以及实现类

public interface IRegisterService {public void register(String name);}
@Service
public class RegisterServiceImpl implements IRegisterService {@Resourceprivate ApplicationEventPublisher applicationEventPublisher;@Overridepublic void register(String name) {UserEntity entity = new UserEntity();entity.setName(name);entity.setId(1L);entity.setMsg("新用户注册同步调用");applicationEventPublisher.publishEvent(entity);}
}

4)测试Controller类,进行测试

@Slf4j
@Controller
public class TestController {@Resourceprivate IRegisterService registerService;@RequestMapping("test")@ResponseBodypublic void test1(String name) {registerService.register(name);log.info("执行同步调用结束");}
}

在浏览器中输入地址:http://localhost/test?name=nik

控制台输出:

handlerEvent: UserEntity(id=1, name=nik, msg=新用户注册同步调用)
执行同步调用结束

示例2:异步发布

1)在启动类添加异步注解 @EnableAsync

2)在监听方法上添加注解 @Async

@Async
@EventListener(condition = "#entity.name != null and #entity.async ")
public void handlerEventAsync(UserEntity entity) {try {TimeUnit.SECONDS.sleep(5);} catch (InterruptedException e) {e.printStackTrace();}log.info("handlerEventAsync: {}", entity);
}

3)在service中添加异步发送方法

@Override
public void registerAsyn(String name) {UserEntity entity = new UserEntity();entity.setName(name);entity.setId(1L);entity.setMsg("新用户注册异步调用");entity.setAsync(true);applicationEventPublisher.publishEvent(entity);
}

4)测试

@RequestMapping("test")
@ResponseBody
public void test(String name) {registerService.registerAsyn(name);log.info("执行异步调用结束");}

控制台输出:

执行异步调用结束
handlerEventAsync: UserEntity(id=1, name=nik, msg=新用户注册异步调用)

示例3:在事务提交后发布事件

比如,用户注册成功后给用户发送成功短信,那么注册成功必然是注册方法事务提交成功后才代表成功。

Spring提供了注解@TransactionalEventListener监听事务事件,在@EventListener基础上增加了属性phase,包含以下四个值:

  • AFTER_COMMIT,事务提交成功后,默认
  • BEFORE_COMMIT,事务提交前
  • AFTER_ROLLBACK,事务回滚后
  • AFTER_COMPLETION,事务完成,AFTER_COMMITAFTER_ROLLBACK

1)自定义事务处理事件

public class RegisterCommitEvent extends ApplicationEvent {@Getter@Setterprivate String msg;@Getter@Setterprivate String name;public RegisterCommitEvent(UserEntity source) {super(source);this.msg = source.getMsg();this.name = source.getName();}
}

2)在处理方法上添加事务注解,@Transactional

@Override
@Transactional
public void registerCommit(String name) {UserEntity entity = new UserEntity();entity.setName(name);entity.setMsg("新用户注册事务提交事件");RegisterCommitEvent registerEvent = new RegisterCommitEvent(entity);userDao.save(entity);// 发送事件applicationEventPublisher.publishEvent(registerEvent);
}

3)添加事务事件监听

@Async
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
public void handlerEventCmmit(RegisterCommitEvent event) {try {TimeUnit.SECONDS.sleep(5);} catch (InterruptedException e) {e.printStackTrace();}log.info("handlerEventCmmit: {}", event);}

4)测试

@RequestMapping("test")
@ResponseBody
public void test(String name) {registerService.registerCommit(name);log.info("执行事务调用结束");}

控制台输出:

执行事务调用结束
handlerEventCmmit: RegisterCommitEvent[source=UserEntity(id=0, name=nik, msg=新用户注册事务提交事件)]

总结

Spring ApplicationEvent事件处理机制使用起来简单方便,可以对程序进行有效解耦。

虽然可以发送任意类型的对象,但是在实际业务中容易产生混乱,建议根据实际业务,定义好各类事件,并在监听方法中实现异步处理。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_998076.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Prompt 共享网站

好用的提示词网站链接&#xff1a; PromptBase | Prompt Marketplace: Midjourney, ChatGPT, DALLE, Stable Diffusion & more.Search 100,000 quality AI prompts from top prompt engineers. Produce better outputs, save on time & API costs, sell your own prom…

鸿蒙Harmony应用开发—ArkTS声明式开发(通用属性:组件标识)

id为组件的唯一标识&#xff0c;在整个应用内唯一。本模块提供组件标识相关接口&#xff0c;可以获取指定id组件的属性&#xff0c;也提供向指定id组件发送事件的功能。 说明&#xff1a; 从API Version 8开始支持。后续版本如有新增内容&#xff0c;则采用上角标单独标记该内容…

Tomcat概念、安装及相关文件介绍

目录 一、web技术 1、C/S架构与B/S架构 1.1 http协议与C/S架构 1.2 http协议与B/S架构 2、前端三大核心技术 2.1 HTML&#xff08;Hypertext Markup Language&#xff09; 2.2 css&#xff08;Cascading Style Sheets&#xff09; 2.3 JavaScript 3、同步和异步 4、…

【翻译】零信任架构准则(一)Introduction to Zero Trust

零信任简介 零信任架构是一种移除内网信任的一种系统设计方法&#xff0c;它假定访问网络的用户都是有敌意的&#xff0c;因此&#xff0c;每个访问请求都需要基于访问防护策略去验证。零信任架构对用户请求的可信度是通过持续构建用户行为上下文来实现&#xff0c;而上下文又…

解决tomcat双击startup.bat一闪而过的问题

这种问题可能是tomcat找不到你的jdk环境配置路径 1、首先在tomcat的bin文件夹找到startup.bat 和catalina.bat两个文件 2、startup.bat用记事本打开 在末尾添加pause 3、保存修改&#xff0c;双击startup.bat如果出现这种问题&#xff0c;就是找不到jdk路径 4、用记事本打开ca…

苹果电脑专业的Mac垃圾清理工具CleanMyMac X4.14.7

CleanMyMac X是一款专业的Mac清理工具&#xff0c;它具有强大的功能和易用的界面&#xff0c;可以帮助用户快速清理Mac上的无用文件和垃圾&#xff0c;优化系统性能&#xff0c;提升电脑运行速度。 该软件的核心功能包括智能扫描与清理、应用程序管理、隐私保护和系统维护等。…

Newsmy储能电源与您相约九州汽车生态博览

2024年3月7日—10日&#xff0c;第24届 深圳国际智慧出行、汽车改装及汽车服务业态博览会&#xff08;以下简称“九州汽车生态博览会”&#xff09;将在深圳国际会展中心&#xff08;宝安&#xff09;举办&#xff0c;Newsmy纽曼集团将在3号馆32523展位&#xff0c;携全系产品与…

高效办公-浏览器基本操作

日常我们使用电脑&#xff0c;其实很大部分是用于网络功能&#xff0c;这里面除了客户端程序剩余的就是通过我们的浏览器获取信息或者使用业务系统了&#xff0c;这里就简单学习下浏览器基本常识与操作。 一、浏览器是什么&#xff1f; 白话讲浏览器就是一个软件&#xff0c;我…

如何在Linux系统部署MeterSphere服务并配置固定公网访问地址

文章目录 推荐 前言1. 安装MeterSphere2. 本地访问MeterSphere3. 安装 cpolar内网穿透软件4. 配置MeterSphere公网访问地址5. 公网远程访问MeterSphere6. 固定MeterSphere公网地址 推荐 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#…

搭建Zabbix监控系统

1、Zabbix基础 Zabbix是一个基于Web界面的企业级开源监控套件&#xff0c;提供分布式系统监控与网络监控功能。具备主机的性能监控&#xff0c;网络设备性能监控&#xff0c;数据库性能监控&#xff0c;多种告警方式&#xff0c;详细报表、图表的绘制等功能。检测的对象可以是L…

20个Python函数程序实例

前面介绍的函数太简单了&#xff1a; 以下是 20 个不同的 Python 函数实例 下面深入一点点&#xff1a; 以下是20个稍微深入一点的&#xff0c;使用Python语言定义并调用函数的示例程序&#xff1a; 20个函数实例 简单函数调用 def greet():print("Hello!")greet…

深度学习500问——Chapter02:机器学习基础(3)

文章目录 2.10 主成分分析&#xff08;PCA&#xff09; 2.10.1 主成分分析&#xff08;PCA&#xff09;思想总结 2.10.2 图解PCA核心思想 2.10.3 PCA算法推理 2.10.4 PCA算法流程总结 2.10.5 PCA算法主要优缺点 2.10.6 降维的必要性及目的 2.10.7 KPCA与PCA的区别 2.11 模型评估…

【k8s】利用crobjob实现定时宿主机集群任务

可以考虑这么个场景&#xff0c;服务商的服务集群以K8S部署在云端&#xff0c;并以一条防火墙策略放通某专线ip或端口&#xff0c;以供外部用户访问。现在出现了这么个需求&#xff0c;由于周末或节假日不上班&#xff0c;客户要求在这些时刻去禁用这些防火墙策略&#xff0c;以…

14:00面试,15:00就出来了,问的问题过于变态了。。。

从小厂出来&#xff0c;没想到在另一家公司又寄了。 到这家公司开始上班&#xff0c;加班是每天必不可少的&#xff0c;看在钱给的比较多的份上&#xff0c;就不太计较了。没想到2月一纸通知&#xff0c;所有人不准加班&#xff0c;加班费不仅没有了&#xff0c;薪资还要降40%…

【RT-DETR有效改进】全新的SOATA轻量化下采样操作ADown(轻量又涨点,附手撕结构图)

一、本文介绍 本文给大家带来的改进机制是利用2024/02/21号最新发布的YOLOv9其中提出的ADown模块来改进我们的Conv模块,其中YOLOv9针对于这个模块并没有介绍,只是在其项目文件中用到了,我将其整理出来用于我们的RT-DETR的项目,经过实验我发现该卷积模块(作为下采样模块)…

场景问题: VisualVM工具Profiler JDBC不是真实执行的SQL

1. 问题 诡异的问题表象&#xff1a; 前端反馈分页接口的Total字段一直为0 使用Visualvm中的 Profiler 注入到应用后&#xff0c;查看JDBC监控得到了分页接口执行的SQL&#xff0c;复制出来执行是55. 此时还没有注意到 IN 的范围中有一个特别的值 NULL &#x1f928; 2. 排查…

Unity 动画(旧版-新版)

旧版 旧版-动画组件&#xff1a;Animation 窗口-动画 动画文件后缀: .anim 将制作后的动画拖动到Animation组件上 旧版的操作 using System.Collections; using System.Collections.Generic; using UnityEngine;public class c1 : MonoBehaviour {// Start is called before…

DNS——域名系统

TCP/IP提供了通过IP地址来连接到设备的功能&#xff0c;但对用户来讲&#xff0c;记住某台设备的IP地址是相当困难的&#xff0c;因此专门设计了一种字符串形式的主机命名机制&#xff0c;这些主机名与IP地址相对应。在IP地址与主机名之间需要有一种转换和查询机制&#xff0c;…

深度学习_19_卷积

理论&#xff1a; 目前问题在于识别图片所需要的模型权重数量会比较大 一般图片像素在12M也就是一千两百万像素&#xff0c;要用模型对其整体识别的话&#xff0c;需要至少一千两百万权重&#xff0c;那也仅仅是线性模型&#xff0c;若用多层感知机的话&#xff0c;模型的数据…

STM32 | STM32时钟分析、GPIO分析、寄存器地址查找、LED灯开发(第二天)

STM32 第二天 一、 STM32时钟分析 寄存器&#xff1a;寄存器的功能是存储二进制代码&#xff0c;它是由具有存储功能的触发器组合起来构成的。一个触发器可以存储1位二进制代码&#xff0c;故存放n位二进制代码的寄存器&#xff0c;需用n个触发器来构成 在计算机领域&#x…