Spring中ApplicationEvent事件的实现

news2025/1/17 0:54:36

1)简介

Spring Event (接口名为Aplication Event)

观察者设计模式,由事件发起者publisher发布事件(指定事件名),事件监听者监听事件(指定事件名)。 好比, A 说了一句话,让B做啥事,B听到了,就去做了

已知好处,先返回用户想要的内容,例如考试系统中计算后的总分先返回用户看,后续的日志记录异步处理,不阻塞线程,抽离业务到异步任务,速度更快

实现流程

  • 自定义事件 (extends ApplicationEvent
  • 定义事件监听器 (implement ApplicationListener)
  • 容器发布事件 (autowired 容器对象,然后 容器对象调用publisher方法指定触发哪个事件)

2)快速入门

2.1)依赖引入

如果引入了springboot的依赖就不用添加了,里面那个starter包含了这个spring依赖

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.2.9.RELEASE</version>
    <scope>compile</scope>
</dependency>

2.2)事件定义

新建一个类,继承applicationEvent使其成为事件类

定义属性,类似实体属性,承载发布事件所传递的参数

其中构造函数必须重写,且形参必须为Ojbect,内部调用super实例化事件类

public class BuyEvent  extends ApplicationEvent {
    private String name;

    public BuyEvent(Object source,String name) {
        super(source);
        this.name=name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

2.3)监听器定义

第一种方法,通过实现ApplicationListener接口

内部重写onApplicationEvent方法,泛型参数需使用BuyEvent,形参才能修改为事件类,方便后续不使用向下转型(强转为BuyEvent)而调用事件的get set方法

@Slf4j
@Component
public class BuyListener implements ApplicationListener<BuyEvent> {
    @Override
    public void onApplicationEvent(BuyEvent buyEvent) {
        System.out.println("购买成功:"+ buyEvent.getName());
    }
}

第二种方法,使用@EventListener注解

事件类作为一个简单的pojo封装数据,不需要@Component加入容器管理

但是监听器是通过ApplicationContext上下文调用的publisher,

需要在容器管理中找有无监听器监听了 XX事件,所以所有监听器的头顶必须带一个@Component

@Component
public class SayListener {

    @EventListener({SayEvent.class})
    public void say(SayEvent sayEvent) {
        String content = sayEvent.getContent();
        System.out.println(content);
    }
}

此时的事件不需要继承ApplicationContent和重写方法,仅需一个构造函数和get set用来传递事件的参数即可

public class SayEvent {
    private String content;

    public String getContent() {
        return content;
    }

    public void setContent(String content) {
        this.content = content;
    }

    public SayEvent(String content) {
        this.content = content;
    }
}

2.4)事件发布

@Service
@Slf4j
public class BuyService {
    @Autowired
    ApplicationContext applicationContext;

    public void buying(String name)  {
            applicationContext.publishEvent(new BuyEvent(this,name));
    }
}

@Service
public class SayService {
    @Autowired
    ApplicationContext applicationContext;

    public void saying(String content){
        applicationContext.publishEvent(new SayEvent(content));
    }
}

2.5)单测

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
</dependency>
@SpringBootTest
@RunWith(SpringRunner.class)
public class BuyServiceTest {

    @Autowired
    BuyService buyService;
    @Autowired
    SayService sayService;
    @Test
    public void testing() {
        buyService.buying("苹果");
        sayService.saying("hahaha");
    }

}

输出测试

image-20241014115939372

3)异步处理

仅需要在listener监听方法上加@Async和sprinboot启动类上加@EnableAsync即可

模拟异步,场景为购买了商品后返回成功消息,同时开启新线程处理记录日志的异步请求

事件

public class LogEvent {
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public LogEvent(String name) {
        this.name = name;
    }
}

监听

@Slf4j
@Component
public class LogListener {

    @Async
    @EventListener({LogEvent.class})
    public void logging(LogEvent logEvent) throws InterruptedException {
        long start = System.currentTimeMillis();
        log.info("日志记录开始为:"+logEvent.getTime());
        Thread.sleep(6000);
        long end = System.currentTimeMillis();
        log.info("记录结束,总耗时为:"+(end-start));
    }
}

发布

@Service
@Slf4j
public class BuyService {
    @Autowired
    ApplicationContext applicationContext;

    public void buying(String name)  {
            long start = System.currentTimeMillis();
            applicationContext.publishEvent(new BuyEvent(this,name));
            applicationContext.publishEvent(new LogEvent(new Date()));
            long end = System.currentTimeMillis();
            log.info("全部任务结束,耗时:"+(end-start)) ;
    }
}

测试

@SpringBootTest
@RunWith(SpringRunner.class)
public class BuyServiceTest {

    @Autowired
    BuyService buyService;
    @Autowired
    SayService sayService;
    @Test
    public void buying() {
     buyService.buying("苹果");
    }

}

结果

image-20241014125559072

这里异步线程提前结束了是因为测试类主线程结束,异步线程终止,可以在异步线程后增加一句话测试不阻塞的特性 或者在生成环境服务下运行,因为主服务springboot会一直运行

image-20241014125822462

image-20241014125815005

可以看到异步事件的发布不阻碍下面语句的执行

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

安卓14无法安装应用解决历程

客户手机基本情况&#xff1a; 安卓14&#xff0c;对应的 targetSdkVersion 34 前天遇到了安卓14适配问题&#xff0c;客户发来的截图是这样的 描述&#xff1a;无法安装我们公司的B应用。 型号&#xff1a;三星google美版 解决步骤&#xff1a; 1、寻找其他安卓14手机测试…

从源码到平台:使用视频美颜SDK构建高性能直播美颜系统详解

本文将深入探讨如何从源码出发&#xff0c;借助视频美颜SDK构建一套高性能的直播美颜系统&#xff0c;涵盖技术架构、核心功能的实现以及性能优化等方面的详解。 一、视频美颜SDK的作用与选择 视频美颜SDK是开发直播美颜系统的基础&#xff0c;它能够提供实时美颜处理功能&am…

STM32的GPIO片上外设

一、STM32的片上外设 片上外设是集成在 MCU 芯片内部的硬件模块&#xff0c;它们通过片内总线与 CPU 直接通信&#xff0c;而不是通过外部引脚或接口连接的设备。 片上外设&#xff1a; 包括 UART、I2C、SPI、ADC、定时器、GPIO、DMA、RTC 等集成在 MCU 内部的模块。这些外设…

《Linux从小白到高手》综合应用篇:深入理解Linux磁盘及IO优化

1. 前言 其实磁盘优化和IO优化&#xff0c;我在前面的其他Linux调优博文中已经讲述过或者涉及过了&#xff0c;但是太过零碎&#xff0c;所以本篇就来集中深入讨论下Linux磁盘和IO调优。 2.磁盘调优 结合我多年的经验&#xff0c;本人认为磁盘调优最重要的是读写性能的提升和…

Unity 实战案例全解析 实现时间停止效果+世界变灰

画面里运动的那个小玩意这么写 using System.Collections; using System.Collections.Generic; using UnityEngine;public class Partol : MonoBehaviour {public Transform pos1;public Transform pos2;public float speed;private Transform target;void Start() {target p…

SpringBoot智能推荐:健康生活新选择

3系统分析 3.1可行性分析 通过对本基于智能推荐的卫生健康系统实行的目的初步调查和分析&#xff0c;提出可行性方案并对其一一进行论证。我们在这里主要从技术可行性、经济可行性、操作可行性等方面进行分析。 3.1.1技术可行性 本基于智能推荐的卫生健康系统采用SSM框架&#…

二叉查找树(Binary Search Tree)Java语言实现

一、二叉查找树 二叉查找树&#xff08;Binary Search Tree&#xff09;&#xff0c;也称为二叉搜索树、有序二叉树&#xff08;Ordered Binary Tree&#xff09;或排序二叉树&#xff08;Sorted Binary Tree&#xff09;。 是指一棵空树或者具有下列性质的二叉树&#xff1a…

Unity DOTS中的Archetype与Chunk

Unity DOTS中的Archetype与Chunk 在Unity中&#xff0c;archetype&#xff08;原型&#xff09;用来表示一个world里具有相同component类型组合的entity。也就是说&#xff0c;相同component类型的entity在Unity内部会存储到一起&#xff0c;共享同一个archetype。 使用这样的设…

JAVA毕业设计191—基于Java+Springboot+vue的电子产品商城管理系统(源代码+数据库)

毕设所有选题&#xff1a; https://blog.csdn.net/2303_76227485/article/details/131104075 基于JavaSpringbootvue的电子产品商城管理系统(源代码数据库)191 一、系统介绍 本项目前后端不分离&#xff0c;分为用户、管理员两种角色 1、用户&#xff1a; 注册、登录、商品…

C++在vscode中的code runner配置/环境配置

C在vscode中快捷运行&#xff08;code runner&#xff09; 一、配置tasks.json 在vscode中创建文件夹或打开文件夹&#xff0c;会发现文件夹下多了一个.vscode文件夹&#xff0c;在该文件夹下创建tasks.json文件&#xff0c;并添加一下内容 {"version": "2.0…

弘景光电:以创新为翼,翱翔光学科技新蓝海

在科技日新月异的今天&#xff0c;光学镜头及模组作为智能设备的核心组件&#xff0c;其重要性日益凸显。广东弘景光电科技股份有限公司&#xff08;以下简称“弘景光电”&#xff09;正是在这一领域中&#xff0c;凭借其卓越的研发实力和市场洞察力&#xff0c;即将在创业板上…

工具篇:(二)MacOS 下载 MySQL 并进行配置连接,使用 VSCode 创建 Node 项目-亲测有效

MacOS 下载 MySQL 并进行配置连接&#xff0c;使用 VSCode 创建 Node 项目 我们将介绍如何在 macOS 上下载和配置 MySQL 数据库&#xff0c;并使用 VSCode 创建一个 Node.js 项目进行测试。通过这些步骤&#xff0c;您将能够顺利地设置开发环境并进行基本的数据操作。 一、删…

【国际学术会议之都,IEEE出版】第四届计算机科学、电子信息工程和智能控制技术国际会议(CEI 2024,2024年11月8-10日)

第四届计算机科学、电子信息工程和智能控制技术国际会议&#xff08;CEI 2024&#xff09; 2024 4th International Conference on Computer Science, Electronic Information Engineering and Intelligent Control Technology 官方信息 会议官网&#xff1a;www.ic-cei.org …

AFSim仿真系统 --- 系统简解_10处理器 (Processors)

处理器 (Processors) 处理器提供了为特定平台定义行为的能力。 大多数处理器由用户使用 AFSIM 脚本语言定义。 以下是一些预定义的处理器类型&#xff1a; WSF_DIRECTION_FINDER_PROCESSORWSF_TRACK_PROCESSORWSF_MESSAGE_PROCESSORWSF_GUIDANCE_COMPUTERWSF_IMAGE_PROCESS…

Android11 USB Camera会出现预览绿屏问题

目录 一、问题描述 二、问题原因 三、解决方法 一、问题描述 DDR容量是4G及以上的机器&#xff0c;USB Camera会出现预览绿屏问题。 串口中会刷如下log: 二、问题原因 RGA2使用超过4G内存会异常&#xff0c;导致USB Camera调用rga相关操作报错&#xff0c;从而预览绿屏 三…

深度学习基础—神经风格迁移

1.什么是神经风格迁移 神经风格迁移就是将一张图片的风格迁移到另一张图片上&#xff0c;生成具有第一张图片风格的新的图片。新图片的主体还是第二张图片&#xff0c;但是风格是第一张图片的。 如下两组图片都是神经风格迁移的例子&#xff1a; 将绘画的风格迁移到真实建筑图片…

树型名称前面插入图片

需求&#xff1a; 搜索树、树型要显示连线&#xff0c;还有名称前带图片 ui组件&#xff1a;https://devui.design/components/zh-cn/overview 直接上代码 [checkable] false 表示取消复选框 <div class"p-sm"><div class"row"><d-sea…

软件开发----Java基础每日刷题(转载于牛客)

1. 对抽象类的描述正确的是() A 抽象类的方法都是抽象方法 B 一个类可以继承多个抽象类 C 抽象类不能有构造方法 D 抽象类不能被实例化 正确答案&#xff1a;D 解析&#xff1a; A.抽象类可以有非抽象的方法&#xff0c;而接口中的方…

Flythings学习(三)界面交互

文章目录 1 界面切换1.1 打开界面1.2 关闭界面 2 界面活动周期2.1 打开不存在页面的活动流程2.2 打开已存在界面&#xff08;被隐藏的界面&#xff09;2.3 关闭界面的流程 1 界面切换 界面切换的相关函数如下 1.1 打开界面 如果需要打开一个界面&#xff0c;在其他界面的控件…

WebSocket状态码及异常报错1006

文章目录 1.WebSocket协议简介2.WebSocket状态码的作用&#xff1a;3.WebSocket状态码1006详解1.问题原因2.解决方案 1.WebSocket协议简介 WebSocket协议是一种基于TCP的协议&#xff0c;它通过在浏览器和服务器之间建立一条持久的双向通信通道&#xff0c;实现了实时的数据传…