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://www.mzph.cn/news/873091.shtml

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

相关文章

【C++】C++ 学生信息管理系统(源码+面向对象)【独一无二】

&#x1f449;博__主&#x1f448;&#xff1a;米码收割机 &#x1f449;技__能&#x1f448;&#xff1a;C/Python语言 &#x1f449;公众号&#x1f448;&#xff1a;测试开发自动化【获取源码商业合作】 &#x1f449;荣__誉&#x1f448;&#xff1a;阿里云博客专家博主、5…

一文-深入了解Ansible常见模块、安装和部署

1 Ansible 介绍 Ansible是一个配置管理系统configuration management system, python 语言是运维人员必须会的语言, ansible 是一个基于python 开发的&#xff08;集合了众多运维工具 puppet、cfengine、chef、func、fabric的优点&#xff09;自动化运维工具, 其功能实现基于ss…

鸿蒙仓颉语言【类型class】

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

算法第十天:leetcode203.移除链表元素

一、203.移除链表元素题目描述 203.移除链表元素的链接如下所示&#xff0c;您可复制下面链接网址进入力扣学习&#xff0c;看题解之前一定要先做一遍哦&#xff01; https://leetcode.cn/problems/remove-linked-list-elements/description/https://leetcode.cn/problems/rem…

26_EfficientNet网络详解

1.1简介 EfficientNet是由Google Research团队开发的一种高效卷积神经网络&#xff08;CNN&#xff09;模型&#xff0c;首次在2019年的论文《EfficientNet: Rethinking Model Scaling for Convolutional Neural Networks》中提出。此模型设计的核心在于平衡网络的深度、宽度以…

如何规划数据科学和机器学习领域的下一步职业发展

。 欢迎来到云闪世界。数据科学和机器学习专业人士面临着来自多个方面的不确定性 欢迎来到云闪世界。全球经济、人工智能工具及其对工作保障的影响&#xff0c;以及不断变化的技术堆栈&#xff0c;仅举几例。如今&#xff0c;谈论职业生涯是否能够抵御经济衰退…

MySQL 进阶(三)【SQL 优化】

1、SQL 优化 1.1、插入数据优化 1.1.1、Insert 优化 1、批量插入 插入多条数据时&#xff0c;不建议使用单条的插入语句&#xff0c;而是下面的批量插入&#xff1a; INSERT INTO tb_name VALUES (),(),(),...; 批量插入建议一次批量 500~100 条&#xff0c;如果数据量比…

GNN学习笔记

1.拉普拉斯矩阵 D是度矩阵&#xff0c;A是邻接矩阵 L的第二个公式常用 L的特征值>0 2.图的整体&#xff0c;节点&#xff0c;边都能代表一个分类/回归问题。 3.GNN的感受野 N-Hop Neighbors&#xff0c;某一点的n阶邻居。n步以内能到达的点。 4.残差连接 最后对图结果的处…

RK3568笔记三十六:LED驱动开发(设备树)

若该文为原创文章&#xff0c;转载请注明原文出处。 记录使用设备树编写一个简单的 LED 灯驱动程序 一、编程思路 程序编写的主要内容为添加 LED 灯的设备树节点、在驱动程序中使用 of 函数获取设备节点中的 属性&#xff0c;编写测试应用程序。 • 首先向设备树添加 LED 设备…

SCSA第八天

防火墙的带宽管理 核心思想 1&#xff0c;带宽限制 --- 限制非关键业务流量占用带宽的比例 2&#xff0c;带宽保证 --- 这里需要保证的是我们关键业务流量&#xff1b;再业务繁忙时&#xff0c;确保关键业务不受影 响&#xff1b; 3&#xff0c;连接数的限制 --- 这也…

如何生成好看的zabbix告警报表并发送邮件

作者 乐维社区&#xff08;forum.lwops.cn&#xff09; 许远 一、场景模拟 小东是一名资深的IT运维人员&#xff0c;其直属领导想要了解公司业务系统的健康状态以及小东日常的工作情况等&#xff0c;要求小东每周统计系统告警情况并发邮件给到他。小东所在公司搭建了一套zabbix…

为什么品牌需要做 IP 形象?

品牌做IP形象的原因有多方面&#xff0c;这些原因共同构成了IP形象在品牌建设中的重要性和价值&#xff0c;主要原因有以下几个方面&#xff1a; 增强品牌识别度与记忆点&#xff1a; IP形象作为品牌的视觉符号&#xff0c;具有独特性和辨识性&#xff0c;能够在消费者心中留…

Linux--网络基础

计算机网络背景 计算机网络背景是一个复杂而丰富的领域&#xff0c;涵盖了从计算机单机模式到网络互联的演变过程&#xff0c;以及网络技术的不断发展和创新。 计算机单机模式和独立发展 在早期&#xff0c;计算机主要以单机模式存在&#xff0c;即每台计算机都是独立的&…

SAC-IA粗配准算法记录

1. 算法思路 SAC-IA(Sample Consensus Initial Aligment,SAC-IA)粗配准算法是一种基于局部特征描述子的点云粗配准算法,其需要计算点云的快速点特征直方图(FPFH)来保持对应点对之间的相似关系,根据相似关系来搜索点云中的对应点。其基本原理是采用采样一致性的思想,通过查…

P2712 摄像头

好久没发帖了&#xff0c;放假了来水一波。 代码&#xff1a; #include<iostream> #include<cstring> #include<algorithm> using namespace std;const int N 200010, mod 80112002;int n, m; int nn; int e[N], h[N], ne[N], idx; int q[N], in[N], chu[N…

宝塔安装RabbitMq教程

需要放开15672端口&#xff0c;默认账号密码为guest/guest

前端开发日记——在MacBook上配置Vue环境

前言 大家好&#xff0c;我是来自CSDN的寄术区博主PleaSure乐事。今天是开始学习vue的第一天&#xff0c;我使用的编译器是vscode&#xff0c;浏览器使用的是谷歌浏览器&#xff0c;后续会下载webstorm进行使用&#xff0c;当前学习阶段使用vscode也是可以的&#xff0c;不用担…

Jupyter Notebook安装及基本使用

Jupyter Notebook安装及基本使用 目录 Jupyter Notebook安装及基本使用方式一&#xff1a;Anaconda直接安装方式二&#xff1a;pip命令安装Jupyter使用虚拟环境 方式一&#xff1a;Anaconda直接安装 安装Anaconda 下载地址&#xff0c;输入邮箱&#xff0c;Windows下载 开始安…

【sgWatermark.js】自定义组件:基于Vue2+html2canvas实现全局水印效果

sgWatermark.js源码 import html2canvas from html2canvas; // npm install --save html2canvas (官网&#xff1a;https://html2canvas.hertzen.com) export default {addWatermark({container document.body, // 水印添加到的容器innerHTML "水印文字内容", //…

最大文件句柄数

优质博文&#xff1a;IT-BLOG-CN 灵感来源 一、什么是文件句柄 文件句柄File Handle是操作系统中用于访问文件的一种数据结构&#xff0c;通常是一个整数或指针。文件句柄用于标识打开的文件&#xff0c;每个打开的文件都有一个唯一的文件句柄。 它们是对文件、网络套接字或…