SpringBoot3框架,事件和监听器、SPI
事件和监听器
生命周期监听
自定义监听器的步骤:
-
编写SpringApplicationRunListener实现类(各个实现方法的功能写在其sout内)
public class MyAppListener implements SpringApplicationRunListener {@Overridepublic void starting(ConfigurableBootstrapContext bootstrapContext) {System.out.println("正在启动");}@Overridepublic void environmentPrepared(ConfigurableBootstrapContext bootstrapContext, ConfigurableEnvironment environment) {System.out.println("环境准备完成");}@Overridepublic void contextPrepared(ConfigurableApplicationContext context) {System.out.println("ioc容器准备完成");}@Overridepublic void contextLoaded(ConfigurableApplicationContext context) {System.out.println("ioc容器加载完成");}@Overridepublic void started(ConfigurableApplicationContext context, Duration timeTaken) {System.out.println("启动完成");}@Overridepublic void ready(ConfigurableApplicationContext context, Duration timeTaken) {System.out.println("应用准备就绪");}@Overridepublic void failed(ConfigurableApplicationContext context, Throwable exception) {System.out.println("应用启动失败");} } -
在
META-INF/spring.factories中配置org.springframework.boot.SpringApplicationRunListener=自定义listener的全限定符,还可以指定一个有参构造器,接受两个参数(SpringApplication application, String[] args)org.springframework.boot.SpringApplicationRunListener=com.ergou.boot3.listener.MyAppListener
以上监听器执行流程
Listener先要从 META-INF/spring.factories 读到
- 引导: 利用 BootstrapContext 引导整个项目启动
- starting:应用开始,SpringApplication的run方法一调用,只要有了 BootstrapContext 就执行
- environmentPrepared:环境准备好(把启动参数等绑定到环境变量中),但是ioc还没有创建;【调一次】
- 启动:
- contextPrepared:ioc容器创建并准备好,但是sources(主配置类)没加载。并关闭引导上下文;组件都没创建 【调一次】
- contextLoaded: ioc容器加载。主配置类加载进去了。但是ioc容器还没刷新(bean没创建) =======截止以前,ioc容器里面还没造bean=======
- started: ioc容器刷新了(所有bean造好了),但是 runner 没调用。
- ready: ioc容器刷新了(所有bean造好了),所有 runner 调用完了。
- 运行: 以前步骤都正确执行,代表容器running。如果不能正常运行(以上的六个步骤有出现错误),调用failed方法。
回调监听器
回调监听器用于感知项目的生命周期的事件
- BootstrapRegistryInitializer: 感知特定阶段:感知引导初始化
META-INF/spring.factories配置- 创建引导上下文
bootstrapContext的时候触发。- ApplicationContextInitializer: 感知特定阶段: 感知ioc容器初始化
META-INF/spring.factories配置- ApplicationListener: 感知全阶段:基于事件机制,感知事件。 一旦到了哪个阶段可以做别的事
META-INF/spring.factories- SpringApplicationRunListener: 感知全阶段生命周期 + 各种阶段都能自定义操作。功能更完善。
META-INF/spring.factories- ApplicationRunner: 感知特定阶段:感知应用就绪Ready。应用启动失败,就不会就绪
@Bean配置- CommandLineRunner: 感知特定阶段:感知应用就绪Ready。应用启动失败,就不会就绪
@Bean配置
配置步骤:
-
自定义监听器,实现相应的监听器接口,重写相应方法,例:
public class MyListener2 implements ApplicationListener<ApplicationEvent> {@Overridepublic void onApplicationEvent(ApplicationEvent event) {System.out.println("感知到事件:"+event);} } -
配置监听器,例:
org.springframework.context.ApplicationListener=com.ergou.boot3.ssm.listener.MyListener2
建议:
- 如果项目启动前做事:
BootstrapRegistryInitializer和ApplicationContextInitializer- 如果想要在项目启动完成后做事:
ApplicationRunner和CommandLineRunner- 如果要干涉生命周期做事:
SpringApplicationRunListener- 如果想要用事件机制:
ApplicationListener
9大事件触发顺序&时机
ApplicationStartingEvent:应用启动但未做任何事情, 除过注册listeners and initializers.ApplicationEnvironmentPreparedEvent: Environment 准备好,但context 未创建.ApplicationContextInitializedEvent: ApplicationContext 准备好,ApplicationContextInitializers 调用,但是任何bean未加载ApplicationPreparedEvent: 容器刷新之前,bean定义信息加载ApplicationStartedEvent: 容器刷新完成, runner未调用=========以下就开始插入了探针机制============
AvailabilityChangeEvent:LivenessState.CORRECT应用存活; 存活探针ApplicationReadyEvent: 任何runner被调用AvailabilityChangeEvent:ReadinessState.ACCEPTING_TRAFFIC就绪探针,可以接请求ApplicationFailedEvent:启动出错
事件驱动开发
事件驱动开发步骤:
首先创建一个事件的发布者EventPublisher类,这个类要实现ApplicationEventPublisherAware,springboot会通过ApplicationEventPublisherAware接口自动注入,接着实现setApplicationEventPublisher方法,并且自定义一个方法来调用底层API发送事件,事件是广播出去的。所有监听这个事件的监听器都可以收到
我们要自定义一个登录成功事件LoginSuccessEvent,这个事件用来绑定用户User类,并且被该功能模块下的service调用
接下来我们要在service的功能代码使用@EventListener注解来进行订阅事件
最后在controller中进行发送事件,相当于原始的调用service功能方法
创建事件发布者
@Service public class EventPublisher implements ApplicationEventPublisherAware {/*** 底层发送事件用的组件,springboot会通过ApplicationEventPublisherAware接口自动注入给我们* 事件是广播出去的。所有监听这个事件的监听器都可以收到* */ApplicationEventPublisher applicationEventPublisher;/*** 所有事件都可以发送* */public void sendEvent(ApplicationEvent event){//调用底层API发送事件applicationEventPublisher.publishEvent(event);}//会被自动调用,把真正发送事件的底层组件注入@Overridepublic void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {this.applicationEventPublisher = applicationEventPublisher;} }创建功能事件
public class LoginSuccessEvent extends ApplicationEvent {/*** 代表是谁成功登录了* */public LoginSuccessEvent(User user) {super(user);} }在service层中订阅相应事件,并做出相应业务处理
@Service public class CouponService {//当loginSuccessEvent事件发生时,@EventListener标注的方法会自动执行,称为订阅@EventListenerpublic void onEvent(LoginSuccessEvent loginSuccessEvent){System.out.println("=======CouponService ======感知到事件"+loginSuccessEvent);User source = (User) loginSuccessEvent.getSource();sendCoupon(source.getUsername());}public void sendCoupon(String username){System.out.println(username+"随机收到了一张优惠券");}}最后在controller层发送相应的事件即可
@RestController public class LoginController {@Autowiredprivate EventPublisher eventPublisher;@GetMapping("/login")public String login(@RequestParam("username") String username,@RequestParam("password")String password){//业务处理登录System.out.println("业务处理登录完成....");User user = new User(username, password);//TODO 发送事件LoginSuccessEvent loginSuccessEvent = new LoginSuccessEvent(user);eventPublisher.sendEvent(loginSuccessEvent);//设计模式:对新增开发,对修改关闭return username+"登录成功";} }
自动配置原理回顾:
- 导入
starter- 依赖导入
autoconfigure- 寻找类路径下
META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports文件- 启动,加载所有
自动配置类xxxAutoConfiguration
- 给容器中配置功能
组件组件参数绑定到属性类中。xxxProperties属性类和配置文件前缀项绑定@Contional派生的条件注解进行判断是否组件生效- 效果:
- 修改配置文件,修改底层参数
- 所有场景自动配置好直接使用
- 可以注入SpringBoot配置好的组件随时使用
SPI机制
- Java中的SPI(Service Provider Interface)是一种软件设计模式,用于在应用程序中动态地发现和加载组件。SPI的思想是,定义一个接口或抽象类,然后通过在classpath中定义实现该接口的类来实现对组件的动态发现和加载。
- SPI的主要目的是解决在应用程序中使用可插拔组件的问题。例如,一个应用程序可能需要使用不同的日志框架或数据库连接池,但是这些组件的选择可能取决于运行时的条件。通过使用SPI,应用程序可以在运行时发现并加载适当的组件,而无需在代码中硬编码这些组件的实现类。
- 在Java中,SPI的实现方式是通过在
META-INF/services目录下创建一个以服务接口全限定名为名字的文件,文件中包含实现该服务接口的类的全限定名。当应用程序启动时,Java的SPI机制会自动扫描classpath中的这些文件,并根据文件中指定的类名来加载实现类。- 通过使用SPI,应用程序可以实现更灵活、可扩展的架构,同时也可以避免硬编码依赖关系和增加代码的可维护性。
在SpringBoot中,通过
META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
来进行SPI
关于配置:
- 自动配置:全部都配置好,什么都不用管。 自动批量导入
- 项目一启动,spi文件中指定的所有都加载。
@EnableXxxx:手动控制哪些功能的开启; 手动导入。
- 开启xxx功能
- 利用 @Import 把此功能要用的组件导入进去
@SpringBootApplication注解及其相关注解
@SpringBootConfiguration
作用与@Configuration一致,容器中的组件,配置类。spring ioc启动就会加载创建这个类的组件
@EnableAutoConfiguration
开启自动配置
@AutoConfigurationPackage
- 利用@Import(AutoConfiguration.Registrar.class)给容器中导入想要的组件
- 把主程序所在的包的所有组件导入进来
@Import(AutoConfigurationImportSelector.class)
加载所有自动配置类(扫描SPI文件:
META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports)@ComponentScan
组件扫描:排除一些组件(排除前面已经扫描过的配置类和自动配置类)
生命周期启动加载机制
自定义starter
例如:
场景:抽取聊天机器人场景,它可以打招呼。
效果:任何项目导入此starter都具有打招呼功能,并且问候语中的人名需要可以在配置文件中修改
创建
自定义starter项目,引入spring-boot-starter基础依赖
编写模块功能,引入模块所有需要的依赖。
编写
xxxAutoConfiguration自动配置类,帮其他项目导入这个模块需要的所有组件
编写配置文件
META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports指定启动需要加载的自动配置
其他项目引入即可使用
自定义的starter的配置方式还可以使用@EnableXxxx的方式
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
@Import(RobotAutoConfiguration.class)
public @interface EnableRobot {}
如此,别人引入starter需要使用 @EnableRobot开启功能
相关文章:
SpringBoot3框架,事件和监听器、SPI
事件和监听器 生命周期监听 自定义监听器的步骤: 编写SpringApplicationRunListener实现类(各个实现方法的功能写在其sout内) public class MyAppListener implements SpringApplicationRunListener {Overridepublic void starting(Configu…...
sadtalker-api/
———— 下载sadtalker工程文件,包括844个模型 。。。。。。。。。。。。。。。。 配置环境: pip源,设置: pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple anaconda prompt, 进入命令行 how在 …...
vue+elementUI实现指定列的单元格可编辑
template中的代码如下: <div v-if"(item.label 高压侧 || item.label 低压侧)&&coloumnHeader.label 单柱片数"><div class"editableCell"><div v-if"item.label 高压侧" dblclick"changeValue(sco…...
RK3568平台开发系列讲解(基础篇)内核是如何发送事件到用户空间
🚀返回专栏总目录 文章目录 一、相关接口函数二、udevadm 命令三、实验沉淀、分享、成长,让自己和他人都能有所收获!😄 一、相关接口函数 kobject_uevent 是 Linux 内核中的一个函数, 用于生成和发送 uevent 事件。 它是 udev 和其他设备管理工具与内核通信的一种方式。…...
力扣---打家劫舍---动态规划
思路 1: 我将res[i]定义为:一定要取第 i 个房子的前提下,能获取的最大金额。那么直接用cnt从头记录到尾,每个房子的res最大值即是答案。那么递推公式是什么?res[i]max(res[i-2],res[i-1],...,res[0])nums[i]。数组初始…...
mac安装rust环境
mac安装rust环境 老规矩官方文档 1. mac官网使用的是脚本安装, 至于为啥没使用brew也没推荐俺也不太清楚 curl --proto https --tlsv1.2 -sSf https://sh.rustup.rs | sh2. 一般来说中途会遇见有一个选择我这里选择直接回车默认安装(如果以后我研究明白的话会进行更新, 现在是…...
1058:求一元二次方程
【题目描述】 利用公式 求一元二次方程axbxc0的根,其中a不等于0。结果要求精确到小数点后5位。 【输入】 输入一行,包含三个浮点数a,b,c(它们之间以一个空格分开),分别表示方程axbxc0的系数。 【输出】 输出一行&…...
GraphQL入门之一对多关联查询
创建 Node.js 的工程 mkdir myapp cd myapp npm init (一路回车)安装依赖包 npm install apollo/server graphql定义 Schema 创建 schema.graphql 文件,内容如下: type Book {title: String!author: Author! }type Author {name: String!books: [Boo…...
MATLAB和Python数值和符号计算可视化物理学气体动能和粒子速度
要点 Python物理学差分数值和符号计算 热动力学计算:统计力学,分子动力学模型 Python寻找弹性物体的运动,LAMMPS 分子动力学模拟器模拟2D气体分子,Python原子模拟绘图,Python数值计算原子平衡性,Python绘制…...
阿里云-零基础入门NLP【基于机器学习的文本分类】
文章目录 学习过程赛题理解学习目标赛题数据数据标签评测指标解题思路TF-IDF介绍TF-IDF 机器学习分类器TF-IDF LinearSVCTF-IDF LGBMClassifier 学习过程 20年当时自身功底是比较零基础(会写些基础的Python[三个科学计算包]数据分析),一开始看这块其实挺懵的&am…...
蓝桥杯模块综合——高质量讲解AT24C02,BS18B20,BS1302,AD/DA(PCF8591),超声波模块
AT24C02——就是一个存储的东西,可以给他写东西,掉电不丢失。 void EEPROM_Write(unsigned char * EEPROM_String,unsigned char addr , unsigned char num) {IIC_Start();IIC_SendByte(0xA0);IIC_WaitAck();IIC_SendByte(addr);IIC_WaitAck();while(nu…...
前端跨平台开发框架:简化多端开发的利器
🤍 前端开发工程师、技术日更博主、已过CET6 🍨 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 🕠 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 🍚 蓝桥云课签约作者、上架课程《Vue.js 和 E…...
cesium.js加载模型后,重新设置旋转角度属性值
// 加载模型var position Cesium.Cartesian3.fromDegrees(longitude, latitude, height);// 计算矩阵var rollAngleDegrees 15; // 设置翻滚角度var rollAngleRadians Cesium.Math.toRadians(rollAngleDegrees); // 将角度转换为弧度var orientation Cesium.Transforms.eas…...
②免费AI软件开发工具测评:通义灵码 VS 码上飞
前言 我又双叒叕来测评了!上次给大家带来的是iFlyCode和CodeFlying两款产品的测评,受到了大家的一致好评~ 今天咱就继续来聊聊,这次我们选的的对象是通义灵码和码上飞,从名字上也能看到出来这两款产品一定是跟软件开发有关系的&…...
幻兽帕鲁游戏搭建(docker)
系列文章目录 第一章: 幻兽帕陆游戏搭建 文章目录 系列文章目录前言一、镜像安装1.创建游戏目录2.拉取镜像3.下载配置文件4.启动游戏 二、自定义配置总结 前言 这段时间一直在写论文还有找工作,也没学啥新技术,所以博客也很长时间没写了&am…...
unity报错出现Asset database transaction committed twice!
错误描述: 运行时报错 Assertion failed on expression: ‘m_ErrorCode MDB_MAP_RESIZED || !HasAbortingErrors()’Asset database transaction committed twice!Assertion failed on expression: ‘errors MDB_SUCCESS || errors MDB_NOTFOUND’ 解决办法&…...
去除项目git的控制 端口号的关闭
以下操作都是在windows下。只是记录一下。 find . -name “.git” | xargs rm -rf 查看所有分支 git branch -a 查看当前分支 git branch -a 切换分支 git chenkout develop docker 查看容器的ip docker inspect -f ‘{{.Name}} - {{range .NetworkSettings.Networks}}{{.IP…...
交叉注意力融合时域、频域特征的FFT + CNN -BiLSTM-CrossAttention电能质量扰动识别模型
往期精彩内容: 电能质量扰动信号数据介绍与分类-Python实现-CSDN博客 Python电能质量扰动信号分类(一)基于LSTM模型的一维信号分类-CSDN博客 Python电能质量扰动信号分类(二)基于CNN模型的一维信号分类-CSDN博客 Python电能质量扰动信号分类(三)基于Transformer…...
简单的Charles抓包教程
安装Charles 安装地址:https://www.charlesproxy.com/download/ 开关本机抓包 一般我们在抓取手机端内容时需要将Proxy菜单栏下的Windows Proxy取消勾选,禁止charles抓取本机上的请求信息。 注:开启电脑端抓包后,会为电脑添加局…...
如何构建Docker自定义镜像
说明:平常我们使用Docker运行各种容器,极大地方便了我们对开发应用的使用,如MySQL、Redis,以及各种中间件,使用时只要拉镜像,运行容器即可。本文介绍如何创建一个Demo,自定义构建一个镜像。 开…...
Android Wi-Fi 连接失败日志分析
1. Android wifi 关键日志总结 (1) Wi-Fi 断开 (CTRL-EVENT-DISCONNECTED reason3) 日志相关部分: 06-05 10:48:40.987 943 943 I wpa_supplicant: wlan0: CTRL-EVENT-DISCONNECTED bssid44:9b:c1:57:a8:90 reason3 locally_generated1解析: CTR…...
Spring Boot 实现流式响应(兼容 2.7.x)
在实际开发中,我们可能会遇到一些流式数据处理的场景,比如接收来自上游接口的 Server-Sent Events(SSE) 或 流式 JSON 内容,并将其原样中转给前端页面或客户端。这种情况下,传统的 RestTemplate 缓存机制会…...
智能仓储的未来:自动化、AI与数据分析如何重塑物流中心
当仓库学会“思考”,物流的终极形态正在诞生 想象这样的场景: 凌晨3点,某物流中心灯火通明却空无一人。AGV机器人集群根据实时订单动态规划路径;AI视觉系统在0.1秒内扫描包裹信息;数字孪生平台正模拟次日峰值流量压力…...
C++:多态机制详解
目录 一. 多态的概念 1.静态多态(编译时多态) 二.动态多态的定义及实现 1.多态的构成条件 2.虚函数 3.虚函数的重写/覆盖 4.虚函数重写的一些其他问题 1).协变 2).析构函数的重写 5.override 和 final关键字 1&#…...
莫兰迪高级灰总结计划简约商务通用PPT模版
莫兰迪高级灰总结计划简约商务通用PPT模版,莫兰迪调色板清新简约工作汇报PPT模版,莫兰迪时尚风极简设计PPT模版,大学生毕业论文答辩PPT模版,莫兰迪配色总结计划简约商务通用PPT模版,莫兰迪商务汇报PPT模版,…...
【Linux】Linux安装并配置RabbitMQ
目录 1. 安装 Erlang 2. 安装 RabbitMQ 2.1.添加 RabbitMQ 仓库 2.2.安装 RabbitMQ 3.配置 3.1.启动和管理服务 4. 访问管理界面 5.安装问题 6.修改密码 7.修改端口 7.1.找到文件 7.2.修改文件 1. 安装 Erlang 由于 RabbitMQ 是用 Erlang 编写的,需要先安…...
WEB3全栈开发——面试专业技能点P4数据库
一、mysql2 原生驱动及其连接机制 概念介绍 mysql2 是 Node.js 环境中广泛使用的 MySQL 客户端库,基于 mysql 库改进而来,具有更好的性能、Promise 支持、流式查询、二进制数据处理能力等。 主要特点: 支持 Promise / async-await…...
Cursor AI 账号纯净度维护与高效注册指南
Cursor AI 账号纯净度维护与高效注册指南:解决限制问题的实战方案 风车无限免费邮箱系统网页端使用说明|快速获取邮箱|cursor|windsurf|augment 问题背景 在成功解决 Cursor 环境配置问题后,许多开发者仍面临账号纯净度不足导致的限制问题。无论使用 16…...
软件工程教学评价
王海林老师您好。 您的《软件工程》课程成功地将宏观的理论与具体的实践相结合。上半学期的理论教学中,您通过丰富的实例,将“高内聚低耦合”、SOLID原则等抽象概念解释得十分透彻,让这些理论不再是停留在纸面的名词,而是可以指导…...
基于微信小程序的作业管理系统源码数据库文档
作业管理系统 摘 要 随着社会的发展,社会的方方面面都在利用信息化时代的优势。互联网的优势和普及使得各种系统的开发成为必需。 本文以实际运用为开发背景,运用软件工程原理和开发方法,它主要是采用java语言技术和微信小程序来完成对系统的…...

