spring事件发布器ApplicationEventPublisher的使用

1、前言

  spring中有一个事件发布器,使用了观察者模式,当有事件发布的时候,事件监听者会立刻收到发布的事件。今天我们来介绍下这个事件发布器怎么使用。

2、简单使用

2.1、创建事件实体类

  事件实体类需要继承ApplicationEvent。我们模拟老师发布事件的诉求。

public class TeacherCommand extends ApplicationEvent {private Integer score;private String name;public TeacherCommand(Object source, Integer score, String name) {super(source);this.name = name;this.score = score;}public Integer getScore() {return score;}public void setScore(Integer score) {this.score = score;}public String getName() {return name;}public void setName(String name) {this.name = name;}
}

2.2、事件发布者

  事件发布者需要实现ApplicationEventPublisherAware接口,实现接口不是必须的,实现接口的目的是为了给applicationEventPublisher赋值。所以只要能给applicationEventPublisher赋值即可。

@Component
public class TeacherCommandPublish implements ApplicationEventPublisherAware {private ApplicationEventPublisher applicationEventPublisher;@Overridepublic void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {this.applicationEventPublisher = applicationEventPublisher;}/*** 发布事件的方法*/public void publishEvent() {TeacherCommand teacherCommand = new TeacherCommand(this, 1, "数学作业");applicationEventPublisher.publishEvent(teacherCommand);System.out.println("事件发布成功:" + Thread.currentThread().getName());}
}

2.3、事件监听者

  事件监听者需要实现ApplicationListener接口。

@Component
public class TeacherCommandListener implements ApplicationListener<TeacherCommand> {@Overridepublic void onApplicationEvent(TeacherCommand teacherCommand) {System.out.println("收到事件:" + teacherCommand.getScore() + ";" + teacherCommand.getName() + ";"+ Thread.currentThread().getName());}
}

2.4、调用事件发布者

    @Autowiredprivate TeacherCommandPublish teacherCommandPublish;@GetMapping("/teacherCommand")public String teacherCommand() {teacherCommandPublish.publishEvent();System.out.println("线程名字:"+Thread.currentThread().getName());return "";}

  输出结果:

收到事件:1;数学作业;http-nio-8083-exec-2
事件发布成功:http-nio-8083-exec-2
线程名字:http-nio-8083-exec-2

  根据输出结果我们可以看到,事件被成功发出和收到了。同时,我们也打印了线程名字,可以得知,事件的发布和监听是同步执行的。因为他们是同一个线程,事件监听者的代码执行完了才会接着执行事件发布者后面的代码。

3、进阶使用

  到这里,我们已经会简单使用spring的事件发布器了,但它是同步执行的,这样其实会影响效率,如果我想改成异步执行的,该怎么做呢?这里我们主要来借助@Async注解来实现。

3.1、配置类上启用EnableAsync

@MapperScan("com.myf.zouding.database.mapper")
@SpringBootApplication(scanBasePackages = {"com.myf"})
@EnableAsync
public class NingJinGameStarterApplication {private static final int NETTY_PORT = 8084;public static void main(String[] args) {SpringApplication.run(NingJinGameStarterApplication.class, args);NettyServer nettyServer =new NettyServer(NETTY_PORT);nettyServer.start();}}

3.2、在事件发布者或监听者方法上使用Async注解

  这里我是在发布者方法上使用了Async注解,也就是实现的发布和接收会由另外一个线程来处理。

@Component
public class TeacherCommandPublish implements ApplicationEventPublisherAware {private ApplicationEventPublisher applicationEventPublisher;@Overridepublic void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {this.applicationEventPublisher = applicationEventPublisher;}/*** 发布事件的方法*/@Asyncpublic void publishEvent() {TeacherCommand teacherCommand = new TeacherCommand(this, 1, "数学作业");applicationEventPublisher.publishEvent(teacherCommand);System.out.println("事件发布成功:" + Thread.currentThread().getName());}
}

3.3、输出结果

线程名字:http-nio-8083-exec-5
收到事件:1;数学作业;task-1
事件发布成功:task-1

  输出结果符合预期。task-1线程负责处理了事件的发布和接收。

3.4、使用线程池配合Async来实现异步,在配置类里实现线程池bean

@MapperScan("com.myf.zouding.database.mapper")
@SpringBootApplication(scanBasePackages = {"com.myf"})
@EnableAsync
public class NingJinGameStarterApplication {private static final int NETTY_PORT = 8084;public static void main(String[] args) {SpringApplication.run(NingJinGameStarterApplication.class, args);NettyServer nettyServer =new NettyServer(NETTY_PORT);nettyServer.start();}@Bean(name = "eventTaskExecutor")public Executor eventTaskExecutor() {ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();executor.setCorePoolSize(5);executor.setMaxPoolSize(10);executor.setQueueCapacity(25);executor.setThreadNamePrefix("event-task-");executor.initialize();return executor;}}

3.5、仅让监听者来异步处理

  上面我们是让事件发布者和监听者都异步来处理,这次我们只让监听者来异步处理,发布者还是同步。

@Component
public class TeacherCommandListener implements ApplicationListener<TeacherCommand> {@Override@Async("eventTaskExecutor")public void onApplicationEvent(TeacherCommand teacherCommand) {System.out.println("收到事件:" + teacherCommand.getScore() + ";" + teacherCommand.getName() + ";"+ Thread.currentThread().getName());}
}

3.6、输出结果

  执行两次:

事件发布成功:http-nio-8083-exec-1
线程名字:http-nio-8083-exec-1
收到事件:1;数学作业;event-task-1
事件发布成功:http-nio-8083-exec-8
线程名字:http-nio-8083-exec-8
收到事件:1;数学作业;event-task-2

  通过结果我们可以看到,事件的发布是由主线程来执行的,事件监听者是由线程池来处理的。符合预期。

4、高阶使用

  思考,如果我们不借助Async注解同时还想实现事件的异步该怎么实现呢?答案是自己实现事件的执行器。关键代码在这个方法里:org.springframework.context.event.SimpleApplicationEventMulticaster#multicastEvent(org.springframework.context.ApplicationEvent, org.springframework.core.ResolvableType),applicationEventPublisher.publishEvent最终也会调用这个方法。
在这里插入图片描述
  也就是要给org.springframework.context.event.SimpleApplicationEventMulticaster#taskExecutor这个属性赋值。

4.1、在配置类里实现给taskExecutor赋值

@MapperScan("com.myf.zouding.database.mapper")
@SpringBootApplication(scanBasePackages = {"com.myf"})
public class NingJinGameStarterApplication {private static final int NETTY_PORT = 8084;public static void main(String[] args) {SpringApplication.run(NingJinGameStarterApplication.class, args);NettyServer nettyServer =new NettyServer(NETTY_PORT);nettyServer.start();}@Bean(name = "applicationEventMulticaster")public SimpleApplicationEventMulticaster simpleApplicationEventMulticaster(@Qualifier("eventTaskExecutor") Executor executor) {SimpleApplicationEventMulticaster eventMulticaster = new SimpleApplicationEventMulticaster();eventMulticaster.setTaskExecutor(executor);return eventMulticaster;}@Bean(name = "eventTaskExecutor")public Executor eventTaskExecutor() {ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();executor.setCorePoolSize(5);executor.setMaxPoolSize(10);executor.setQueueCapacity(25);executor.setThreadNamePrefix("event-task-");executor.initialize();return executor;}}

  把其它地方的异步注解Async去掉,执行输出结果

事件发布成功:http-nio-8083-exec-1
收到事件:1;数学作业;event-task-2
线程名字:http-nio-8083-exec-1
事件发布成功:http-nio-8083-exec-7
线程名字:http-nio-8083-exec-7
收到事件:1;数学作业;event-task-1

  可以看到,事件的监听者是由线程池来处理的,符合预期。

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

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

相关文章

【51项目】基于51单片机protues交通灯的设计(完整资料源码)

基于51单片机protues交通灯的设计 一、 项目背景 1.1背景 随着科技的不断发展&#xff0c;LED技术在交通领域的应用越来越广泛。LED模拟交通灯作为一种新型的交通信号控制设备&#xff0c;以其高效、节能、环保等优点&#xff0c;逐渐取代了传统的交通信号灯。近年来&#xff…

【jenkins+cmake+svn管理c++项目】msbuild: command not found

一、前言 jenkins中配置cmakeVS的编译构建过程&#xff0c;需要用到MSBuild这个工具来完成VS工作&#xff0c;MSBuild的安装配置方法见&#xff1a;windows编译环境和工具配置 MSBuildCMAKE的编译可以用脚本来完成&#xff0c;我在jenkins的构建步骤中添加了一个ExecuteShell…

【人工智能】Transformers之Pipeline(三):文本转音频(text-to-audio/text-to-speech)

​​​​​​​ 一、引言 pipeline&#xff08;管道&#xff09;是huggingface transformers库中一种极简方式使用大模型推理的抽象&#xff0c;将所有大模型分为音频&#xff08;Audio&#xff09;、计算机视觉&#xff08;Computer vision&#xff09;、自然语言处理&#x…

数据库如何简单入手学习

人不走空 &#x1f308;个人主页&#xff1a;人不走空 &#x1f496;系列专栏&#xff1a;算法专题 ⏰诗词歌赋&#xff1a;斯是陋室&#xff0c;惟吾德馨 作为一个后端开发人员&#xff0c;应该没有不接触数据库的&#xff0c;数据库操作优化也是后端面试人员的重点面…

2024辽宁省数学建模B题【钢铁产品质量优化】原创论文分享

大家好呀&#xff0c;从发布赛题一直到现在&#xff0c;总算完成了2024 年辽宁省大学数学建模竞赛B题钢铁产品质量优化完整的成品论文。 本论文可以保证原创&#xff0c;保证高质量。绝不是随便引用一大堆模型和代码复制粘贴进来完全没有应用糊弄人的垃圾半成品论文。 B题论文…

Visual Studio 智能代码插件:Fitten Code

Fitten Code 是由非十大模型驱动的AI编程助手&#xff0c;它可以自动生成代码&#xff0c;提升开发效率&#xff0c;协助调试 Bug&#xff0c;节省时间。还可以对话聊天&#xff0c;解决编程碰到的问题。 Fitten Code 免费且多种编程语言&#xff0c;包括 Python、C、Javascri…

在VS2022中通过Nuget将vcpkg环境集成/卸载到c++项目

在VS2022中通过Nuget将vcpkg环境集成/卸载到c项目 vcpkg是微软和C社区维护的免费开源C/C包管理器。利用它&#xff0c;可以一条命令编译安装用户所需的库&#xff1b;提供CMake配置文件&#xff1b;并且对于Windows开发者&#xff0c;在Visual Studio中集成后还可以自动链接静…

鸿蒙仓颉语言【类型class】

类与结构&#xff08;class & struct&#xff09; 面向对象的编程语言&#xff0c;必不可少的基础元素&#xff0c;类或者叫类型&#xff0c;在仓颉中类可以抽象(abstract)、继承&#xff08;<:&#xff09;&#xff0c;公开&#xff08;Public&#xff09;或者私有&am…

redis数据库(下)

集合键值对 集合的每一个元素也是字符串格式数据,是无序集合,并且元素不可重复(自动去重) 1.集合的创建和添加命令 sadd命令:无责创建有责添加 sadd 键名 元素1 元素2......... 注意:再次添加元素时,如果触发了集合的唯一性,那么命令执行结果就为0,表示执行失败…

windows edge自带的pdf分割工具(功能)

WPS分割pdf得会员&#xff0c;要充值&#xff01;网上一顿乱找&#xff0c;发现最简单&#xff0c;最好用&#xff0c;免费的还是回到Windows。 Windows上直接在edge浏览器打开PDF&#xff0c;点击 打印 按钮,页面下选择对应页数 打印机 选择 另存为PDF&#xff0c;然后保存就…

CE入门教程

【半小时搞懂《CE官方教程》2—9关】https://www.bilibili.com/video/BV1et4y1J75o?vd_source7ad69e0c2be65c96d9584e19b0202113 CE修改器使用教程 [入门篇] - lyshark - 博客园 (cnblogs.com) 第一关 附加进程 第二关 静态地址的值更改 就是找到数值,更改 首次扫描 SM他,变…

LeetCode-随机链表的复制

. - 力扣&#xff08;LeetCode&#xff09; 本题思路&#xff1a; 首先注意到随机链表含有random的指针&#xff0c;这个random指针指向是随机的&#xff1b;先一个一个节点的拷贝&#xff0c;并且把拷贝的节点放在拷贝对象的后面&#xff0c;再让拷贝节点的next指向原链表拷贝…

基于QEMU-aarch64学习UEFI(EDK2)-8QEMU固件变量存储

1 基于QEMU-aarch64学习UEFI(EDK2)-8QEMU固件变量存储 文章目录 1 基于QEMU-aarch64学习UEFI(EDK2)-8QEMU固件变量存储1.1 fd固件分析1.2 QEMU_VARS.fd分析1.2.1 QEMU_VARS.fd与QEMU_EFI.fd二合一1.2.2 错误分析1.2.2.1 gEdkiiNvVarStoreFormattedGuid1.2.2.2 SupportFvb1.2.2.…

打破运维“冷门槛“|暴雨液冷数据中心方案再升级

如果将数据比喻为驱动世界运转的新引擎&#xff0c;那数据中心便是为引擎提供源源不断动力的泵站。但随着泵站功率的日益增强&#xff0c;热浪成了不可避免的副产品。如何将数据热能转化为科技动能&#xff0c;是人工智能可持续发展的重要前提。 液冷技术&#xff0c;不仅可实现…

基于Java的在线考试系统

你好呀&#xff0c;我是计算机学姐码农小野&#xff01;如果有相关需求&#xff0c;可以私信联系我。 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;Java MySQL B/S架构 SpringBoot框架 工具&#xff1a;Eclipse、MySQL环境配置工具 系统展示 首…

Hyper-v创建二代虚拟机无法进入bios问题解决

首先要确定从dvd驱动在上面&#xff0c;如果不在则把它向上移动然后保存。 启动虚拟机会进入下面界面 然后点下最左边的按钮然后疯狂点击f2(有的电脑是fnf2) 就可以顺利进入bios引导界面。

InstaPrism能否平替BayesPrism(贝叶斯棱镜)?

上一期内容提到了BayesPrism算法用于单细胞数据的反卷积&#xff0c;BayesPrism算法在实际应用中非常占用计算资源以及消耗使用者的时间。那么是否有较好的替代包呢&#xff1f; 曾老师告诉了我一个R包—InstaPrism&#xff0c;他希望我将其和BayesPrism算法做个对比。 开发者…

Axure RP移动端医院在线挂号app问诊原型图模板

医疗在线挂号问诊Axure RP原型图医院APP原形模板&#xff0c;是一款原创的医疗类APP&#xff0c;设计尺寸采用iPhone13&#xff08;375*812px&#xff09;&#xff0c;原型图上加入了仿真手机壳&#xff0c;使得预览效果更加逼真。 本套原型图主要功能有医疗常识科普、医院挂号…

鸿蒙Navigation路由能力汇总

基本使用步骤&#xff1a; 1、新增配置文件router_map&#xff1a; 2、在moudle.json5中添加刚才新增的router_map配置&#xff1a; 3、使用方法&#xff1a; 属性汇总&#xff1a; https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-basic-compone…

mediasoup企业级会议并发方案设计

mediasoup单服务企业级部署方案 网络环境如图 服务器要求: 单个mediasoup稳定支持200-300路流&#xff0c;为了增加服务的并发&#xff0c;在一个服务器上部署5个信令服务及mediasoup服务 单台服务器32核cpu&#xff0c;32G内存&#xff0c;带宽2000M及以上 集群部署方案图…