Spring Boot - Application Events 同步 VS 异步 发布订阅事件实战

文章目录

  • Pre
  • Code
  • 基础工程
    • 启动类
    • 切入口
    • 事件
  • 发布事件
  • 同步 Listener
  • 异步Listener
    • 增加@EnableAsync
    • 增加 @Async
  • 测试

在这里插入图片描述


Pre

Spring Boot - Application Events 的发布顺序_ApplicationStartingEvent

Spring Boot - Application Events 的发布顺序_ApplicationEnvironmentPreparedEvent

Spring Boot - Application Events 的发布顺序_ApplicationContextInitializedEvent

Spring Boot - Application Events 的发布顺序_ApplicationPreparedEvent

Spring Boot - Application Events 的发布顺序_ContextRefreshedListener

Spring Boot - Application Events 的发布顺序_ApplicationStartedEvent

Spring Boot - Application Events 的发布顺序_AvailabilityChangeEvent

Spring Boot - Application Events 的发布顺序_ApplicationReadyEvent

Spring Boot - Application Events 的发布顺序_ApplicationFailedEvent

Spring Boot - ApplicationRunner && CommandLineRunner扩展接口


Code

在这里插入图片描述


基础工程

启动类

@SpringBootApplication 
public class LifeCycleApplication {/*** 除了手工add , 在 META-INF下面 的 spring.factories 里增加* org.springframework.context.ApplicationListener=自定义的listener 也可以** @param args*/public static void main(String[] args) {SpringApplication.run(LifeCycleApplication.class, args);}
}

META-INF中增加 spring.factories文件

org.springframework.context.ApplicationListener=\
com.artisan.practise.listeners.SpringBuiltInEventsListener

切入口

package com.artisan.practise.listeners;import com.artisan.practise.publish.Publisher;
import org.springframework.beans.BeansException;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.boot.context.event.SpringApplicationEvent;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationListener;/*** @author 小工匠* @version 1.0* @mark: show me the code , change the world*/
public class SpringBuiltInEventsListener implements ApplicationListener<SpringApplicationEvent>, ApplicationContextAware {private ApplicationContext applicationContext;@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {this.applicationContext = applicationContext;}@Overridepublic void onApplicationEvent(SpringApplicationEvent event) {System.out.println("SpringApplicationEvent Received - " + event);// Initializing publisher for custom eventthis.initPublisher(event);}private void initPublisher(SpringApplicationEvent event) {if (event instanceof ApplicationReadyEvent) {this.applicationContext.getBean(Publisher.class).publishEvent();}}
}

事件

package com.artisan.practise.events;import org.springframework.context.ApplicationEvent;/*** @author 小工匠* @version 1.0* @mark: show me the code , change the world*/
public class UserCreatedEvent extends ApplicationEvent {private static final long serialVersionUID = 1L;private String name;public UserCreatedEvent(Object source, String name) {super(source);this.name = name;}public String getName() {return this.name;}}
package com.artisan.practise.events;/*** @author 小工匠* @version 1.0* @mark: show me the code , change the world*/
public class UserRemovedEvent {public String name;public UserRemovedEvent(String name) {this.name = name;}public String getName() {return this.name;}}


发布事件

package com.artisan.practise.publish;import com.artisan.practise.events.UserCreatedEvent;
import com.artisan.practise.events.UserRemovedEvent;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Component;/*** @author 小工匠* @version 1.0* @mark: show me the code , change the world*/
@Component
public class Publisher {@Autowiredprivate ApplicationEventPublisher publisher;public void publishEvent() {System.out.println("========================"  + Thread.currentThread().getName());// Async Eventpublisher.publishEvent("I'm Async");// @EventListener Annotated and ApplicationListenerpublisher.publishEvent(new UserCreatedEvent(this, "Artisan"));publisher.publishEvent(new UserRemovedEvent("Artisan"));// Conditional Listenerpublisher.publishEvent(new UserCreatedEvent(this, "reflectoring"));publisher.publishEvent(new UserRemovedEvent("reflectoring"));}}

同步 Listener

package com.artisan.practise.listeners;import com.artisan.practise.events.UserCreatedEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;
/*** @author 小工匠* @version 1.0* @mark: show me the code , change the world*/
@Component
class UserCreatedListener implements ApplicationListener<UserCreatedEvent> {@Overridepublic void onApplicationEvent(UserCreatedEvent event) {System.out.println(String.format("%s - User created: %s",Thread.currentThread().getName() , event.getName()));}
}
package com.artisan.practise.listeners;import com.artisan.practise.events.UserRemovedEvent;
import com.artisan.practise.response.ReturnedEvent;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
import org.springframework.transaction.event.TransactionPhase;
import org.springframework.transaction.event.TransactionalEventListener;/*** @author 小工匠* @version 1.0* @mark: show me the code , change the world*/
@Component
public class UserRemovedListener {@EventListenerReturnedEvent handleUserRemovedEvent(UserRemovedEvent event) {System.out.println(String.format("%s - User removed (@EventListerner): %s", Thread.currentThread().getName(), event.getName()));// Spring will send ReturnedEvent as a new eventreturn new ReturnedEvent();}// Listener to receive the event returned by Spring@EventListenervoid handleReturnedEvent(ReturnedEvent event) {System.out.println(String.format("%s - ReturnedEvent received.", Thread.currentThread().getName()));}@EventListener(condition = "#event.name eq 'reflectoring'")void handleConditionalListener(UserRemovedEvent event) {System.out.println(String.format("%s - User removed (Conditional): %s", Thread.currentThread().getName(), event.getName()));}@TransactionalEventListener(condition = "#event.name eq 'reflectoring'", phase = TransactionPhase.AFTER_COMPLETION)void handleAfterUserRemoved(UserRemovedEvent event) {System.out.println(String.format("%s - User removed (@TransactionalEventListener): %s", Thread.currentThread().getName(), event.getName()));}}

异步Listener

增加@EnableAsync

启动类增加@EnableAsync

@SpringBootApplication
@EnableAsync
public class LifeCycleApplication {}

@EnableAsync 是一个在 Spring 框架中使用的注解,它用于启用 Spring 的异步执行功能。当在一个配置类上加上 @EnableAsync 注解时,Spring 容器会设置异步任务执行的支持。这允许你将任务标记为异步,并且可以在不同的线程中执行它们,从而提高应用程序的响应能力和吞吐量。
以下是一些关键点,用以解释 @EnableAsync 注解的功能和用法:

  1. 异步执行: 在 Spring 应用中,你可以使用 @Async 注解来标记一个方法为异步执行。当方法被调用时,它将在一个单独的线程中运行,而不是在调用线程中立即执行。

  2. 启用异步执行: 为了使 @Async 注解生效,必须在 Spring 应用程序的配置中启用异步支持。这通常是通过在 Spring 配置类上添加 @EnableAsync 注解来实现的。

  3. 线程池: @EnableAsync 注解允许你定义一个自定义的线程池,Spring 会使用这个线程池来执行异步任务。如果你没有提供线程池,Spring 会使用默认的线程池。

  4. 异常处理: 异步方法执行中发生的异常通常不会传递给调用者。@EnableAsync 支持异常处理配置,允许你定义如何处理这些异常。

  5. 调度器: 你可以指定一个 TaskScheduler Bean,Spring 使用它来调度异步任务。默认情况下,Spring 容器会创建一个 SimpleAsyncTaskExecutor 实例。

  6. 顺序执行: 如果你需要确保某些异步方法按照严格的顺序执行,可以使用 @Async 注解的 dependsOn 属性来指定依赖关系。

使用 @EnableAsync 注解可以让开发者轻松地构建高并发的应用程序,提高应用程序处理大量并发请求的能力,同时保持代码的清晰和易管理性。在微服务架构和分布式系统中,异步通信是提高系统解耦和性能的关键技术之一。


增加 @Async

增加 @Async

package com.artisan.practise.listeners;import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;@Component
class AsyncListener {@Async@EventListenervoid handleAsyncEvent(String event) {System.out.println(String.format("%s - Async event recevied: %s  ",  Thread.currentThread().getName(), event));}}

@Async 是一个方法级别的注解,在 Spring 框架中用于标识一个方法应该以异步方式执行。当一个方法被标记为 @Async 时,它将在一个单独的线程中运行,而不是在调用它的线程中立即执行。这种方式可以避免阻塞调用线程,从而提高应用程序的响应能力和吞吐量。
以下是一些关于 @Async 注解的关键点:

  1. 异步方法执行: @Async 注解允许你将方法的执行放到一个单独的线程中,这样主线程就可以立即返回,继续处理其他任务。
  2. 线程池: @Async 注解通常与 @EnableAsync 注解一起使用,后者启用了异步支持并定义了一个线程池。异步方法通常会在这个线程池中分配线程来执行。
  3. 异常处理: 异步方法执行过程中出现的异常通常不会传递给调用者。但是,可以通过配置 AsyncUncaughtExceptionHandler 来处理这些异常。
  4. 调度器: @Async 注解可以指定一个 TaskScheduler Bean,它负责调度异步任务的执行。如果没有指定,Spring 会默认使用一个 SimpleAsyncTaskExecutor
  5. 顺序执行: 如果需要确保某些异步方法按照严格的顺序执行,可以使用 @Async 注解的 dependsOn 属性来指定依赖关系。
  6. 触发器: @Async 方法可以由其他 @Async 方法触发,这允许创建异步的工作流和回调。
  7. 注解兼容性: @Async 注解可以与 @Transactional 注解一起使用,但是需要确保事务性注解和异步注解在方法上的使用是兼容的。

异步编程 - 08 Spring框架中的异步执行_TaskExecutor接口和@Async应用篇

异步编程 - 09 Spring框架中的异步执行_@Async注解异步执行原理&源码解析


测试

在这里插入图片描述

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

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

相关文章

国内镜像:极速下载编译WebRTC源码(For Android/Linux/IOS)(二十四)

简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长! 优质专栏:Audio工程师进阶系列【原创干货持续更新中……】🚀 优质专栏:多媒体系统工程师系列【原创干货持续更新中……】🚀 人生格言: 人生从来没有捷径,只…

LeetCode 232.用栈实现队列(详解) (๑•̌.•๑)

题目描述&#xff1a; 解题思路&#xff1a; 创建两个栈&#xff0c;一个用于入数据&#xff0c;一个用于出数据。分别是pushST和popST; 1.如果是入数据就直接入进pushST 2.如果是出数据&#xff0c;先检查popST中有无数据&#xff0c;如果有数据&#xff0c;就直接出。如果没…

2024年中职网络安全——Windows操作系统渗透测试(Server2105)

Windows操作系统渗透测试 任务环境说明&#xff1a; 服务器场景&#xff1a;Server2105服务器场景操作系统&#xff1a;Windows&#xff08;版本不详&#xff09;&#xff08;封闭靶机&#xff09;需要环境加Q 目录 1.通过本地PC中渗透测试平台Kali对服务器场景进行系统服务…

ubuntu安装mysql(tar.xz)

0:本机Ubuntu的版本为 腾讯云 18.04 1&#xff1a;下载地址 MySQL &#xff1a;&#xff1a; 下载 MySQL 社区服务器 2&#xff1a;上传文件到服务器 3:解压 sudo sumv mysql-8.2.0-linux-glibc2.17-x86_64-minimal.tar.xz /usrtar -xvf mysql-8.2.0-linux-glibc2.17-x86_6…

逆变器3前级推免(高频变压器)

一节电池标压是在2.8V—4.2V之间&#xff0c;所以24V电压需要大概七节电池串联。七节电池电压大概在19.6V—29.4V之间。 从24V的电池逆变到到220V需要升压的过程。那么我们具体需要升压到多少&#xff1f; 市电AC220V是有效值电压&#xff0c;峰值电压是220V*1.414311V 如果…

Ubuntu下AI4Green开源ELN服务的简单部署

主部署程序&#xff1a;AI4Green 配置参考这篇文档&#xff1a;AI4Green开源ELN&#xff08;电子实验记录本&#xff09;-CSDN博客 流量转发和负载均衡&#xff1a;使用Nginx 配置参考这篇文档&#xff1a;Nginx负载均衡-CSDN博客 SSL配置部分参考这篇文档&#xff1a; 设置…

Android Lint的使用

代码检查方式一&#xff1a; Android Studio使用Lint进行代码检查 找到Analyze目录下的Inspect Code检查代码选项点击然后弹出下面这个框框&#xff0c;在这个列表选项中我们可以选择Inspect Code的范围&#xff0c;点击OK 待分析完毕后&#xff0c;我们可以在Inspection栏目中…

WPF XAML(一)

一、XAML的含义 问&#xff1a;XAML的含义是什么&#xff1f;为什么WPF中会使用XAML&#xff1f;而不是别的&#xff1f; 答&#xff1a;在XAML是基于XML的格式&#xff0c;XML的优点在于设计目标是具有逻辑性易读而且简单内容也没有被压缩。 其中需要提一下XAML文件在 Visu…

Java并查集设计以及路径压缩实现

Java全能学习面试指南&#xff1a;https://javaxiaobear.cn 并查集是一种树型的数据结构 &#xff0c;并查集可以高效地进行如下操作&#xff1a; 查询元素p和元素q是否属于同一组合并元素p和元素q所在的组 1、并查集的结构 并查集也是一种树型结构&#xff0c;但这棵树跟我们之…

Unity C# 枚举多选

枚举多选 &#x1f96a;例子&#x1f354;判断 &#x1f96a;例子 [System.Flags]public enum TestEnum{ None 0,Rooms 1 << 1,Walls1<<2,Objects1<<3,Slabs 1 << 4,All Rooms|Walls|Objects|Slabs}&#x1f354;判断 TestEnum test TestEnum.R…

C++ 手写堆 || 堆模版题:堆排序

输入一个长度为 n 的整数数列&#xff0c;从小到大输出前 m 小的数。 输入格式 第一行包含整数 n 和 m 。 第二行包含 n 个整数&#xff0c;表示整数数列。 输出格式 共一行&#xff0c;包含 m 个整数&#xff0c;表示整数数列中前 m 小的数。 数据范围 1≤m≤n≤105 &…

linux(ubuntu)中crontab定时器命令详解 以及windows中定时器

linux&#xff08;ubuntu&#xff09;中crontab定时器命令详解 crontab 是一个用于创建、编辑和管理用户的定时任务的命令&#xff0c;它可以让用户在指定的时间自动执行指定的命令或脚本。 基本语法 -e&#xff1a;编辑用户的 crontab 文件&#xff1b;-l&#xff1a;列出用…

MySQL的导入导出及备份

一.准备导入之前 二.navicat导入导出 ​编辑 三.MySQLdump命令导入导出 四.load data file命令的导入导出 五.远程备份 六. 思维导图 一.准备导入之前 需要注意&#xff1a; 在导出和导入之前&#xff0c;确保你有足够的权限。在进行导入操作之前&#xff0c;确保目标数据…

有了 Prisma,就别用 TypeORM 了

要说2024 年 Node.js 的 ORM 框架应该选择哪个&#xff1f;毫无疑问选 Prisma。至于为何&#xff0c;请听我细细道来。 本文面向的对象是饱受 TypeORM 折磨的资深用户(说的便是我自己)。只对这两个 ORM 框架从开发体验上进行对比&#xff0c;你也可以到 这里 查看 Prisma 官方对…

安装nvidia driver出现 the cc vision check falied

这里提示说的需要gcc12,但是我只有gcc11,所以就报错了&#xff0c;说一说我自己的解决方法&#xff1a; 安装gcc12和g12,再切换版本为gcc12 安装gcc12: sudo apt install gcc-12安装g12: sudo apt -y install g-12切换版本&#xff1a;参考博客

R语言【paleobioDB】——pbdb_map():根据化石记录绘制地图

Package paleobioDB version 0.7.0 paleobioDB 包在2020年已经停止更新&#xff0c;该包依赖PBDB v1 API。 可以选择在Index of /src/contrib/Archive/paleobioDB (r-project.org)下载安装包后&#xff0c;执行本地安装。 Usage pbdb_map (data, col.int"white" ,p…

如何使用PR制作抖音视频?抖音短视频创作素材剪辑模板PR项目工程文件

如何使用PR软件制作抖音视频作品&#xff1f;Premiere Pro 抖音短视频创作素材剪辑模板PR项目工程文件。 3种分辨率&#xff1a;10801920、10801350、10801080。 来自PR模板网&#xff1a;https://prmuban.com/37058.html

用React给XXL-JOB开发一个新皮肤(二):目录规划和路由初始化

目录 一. 简述二. 目录规划三. Vite 配置 3.1. 配置路径别名3.2. 配置 less 四. 页面 4.1. 入口文件4.2. 骨架文件4.3. 普通页面 五. 路由配置六. 预览启动 一. 简述 上一篇文章我们介绍了项目初始化&#xff0c;此篇文章我们会先介绍下当前项目的目录规划&#xff0c;接着对…

Python 中的字符串分割函数 split() 详解

更多Python学习内容&#xff1a;ipengtao.com 在 Python 编程中&#xff0c;处理字符串是一项常见的任务。字符串分割是其中的一个常见操作&#xff0c;而 Python 提供了强大的 split() 函数&#xff0c;用于将字符串拆分成多个部分。本文将详细介绍 split() 函数的用法、参数和…

Openstack组件glance对接swift

2、glance对接swift &#xff08;1&#xff09;可直接在数据库中查看镜像存放的位置、状态、id等信息 &#xff08;2&#xff09;修改glance-api的配置文件&#xff0c;实现对接swift存储&#xff08;配置文件在/etc/glance/glance-api.conf&#xff0c;建议先拷贝一份&#x…