聊聊springboot的启动事件
序
本文主要研究一下springboot的启动事件
SpringApplicationEvent
org/springframework/boot/context/event/SpringApplicationEvent.java
public abstract class SpringApplicationEvent extends ApplicationEvent {private final String[] args;public SpringApplicationEvent(SpringApplication application, String[] args) {super(application);this.args = args;}public SpringApplication getSpringApplication() {return (SpringApplication) getSource();}public final String[] getArgs() {return this.args;}}
SpringApplicationEvent继承了ApplicationEvent,它有几个子类分表是ApplicationStartingEvent、ApplicationEnvironmentPreparedEvent、ApplicationContextInitializedEvent、ApplicationPreparedEvent、ApplicationStartedEvent、ApplicationReadyEvent,期间有异常则抛出ApplicationFailedEvent
SpringApplication.run
org/springframework/boot/SpringApplication.java
public ConfigurableApplicationContext run(String... args) {StopWatch stopWatch = new StopWatch();stopWatch.start();ConfigurableApplicationContext context = null;Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();configureHeadlessProperty();SpringApplicationRunListeners listeners = getRunListeners(args);listeners.starting();try {ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);configureIgnoreBeanInfo(environment);Banner printedBanner = printBanner(environment);context = createApplicationContext();exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,new Class[] { ConfigurableApplicationContext.class }, context);prepareContext(context, environment, listeners, applicationArguments, printedBanner);refreshContext(context);afterRefresh(context, applicationArguments);stopWatch.stop();if (this.logStartupInfo) {new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);}listeners.started(context);callRunners(context, applicationArguments);}catch (Throwable ex) {handleRunFailure(context, ex, exceptionReporters, listeners);throw new IllegalStateException(ex);}try {listeners.running(context);}catch (Throwable ex) {handleRunFailure(context, ex, exceptionReporters, null);throw new IllegalStateException(ex);}return context;}
SpringApplication的run方法,先触发listeners.starting(),然后执行了prepareEnvironment,之后createApplicationContext,再进行prepareContext和refreshContext,最后触发listeners.started(context),之后执行callRunners,最后触发listeners.running(context),如有异常则会执行handleRunFailure
prepareEnvironment
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,ApplicationArguments applicationArguments) {// Create and configure the environmentConfigurableEnvironment environment = getOrCreateEnvironment();configureEnvironment(environment, applicationArguments.getSourceArgs());ConfigurationPropertySources.attach(environment);listeners.environmentPrepared(environment);bindToSpringApplication(environment);if (!this.isCustomEnvironment) {environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment,deduceEnvironmentClass());}ConfigurationPropertySources.attach(environment);return environment;}
prepareEnvironment会触发listeners.environmentPrepared(environment),即发布ApplicationEnvironmentPreparedEvent
prepareContext
private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {context.setEnvironment(environment);postProcessApplicationContext(context);applyInitializers(context);listeners.contextPrepared(context);if (this.logStartupInfo) {logStartupInfo(context.getParent() == null);logStartupProfileInfo(context);}// Add boot specific singleton beansConfigurableListableBeanFactory beanFactory = context.getBeanFactory();beanFactory.registerSingleton("springApplicationArguments", applicationArguments);if (printedBanner != null) {beanFactory.registerSingleton("springBootBanner", printedBanner);}if (beanFactory instanceof DefaultListableBeanFactory) {((DefaultListableBeanFactory) beanFactory).setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);}if (this.lazyInitialization) {context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());}// Load the sourcesSet<Object> sources = getAllSources();Assert.notEmpty(sources, "Sources must not be empty");load(context, sources.toArray(new Object[0]));listeners.contextLoaded(context);}
prepareContext会触发listeners.contextPrepared(context),即发布ApplicationContextInitializedEvent,执行完成之后触发listeners.contextLoaded(context),即发布ApplicationPreparedEvent
refreshContext
private void refreshContext(ConfigurableApplicationContext context) {refresh(context);if (this.registerShutdownHook) {try {context.registerShutdownHook();}catch (AccessControlException ex) {// Not allowed in some environments.}}}protected void refresh(ApplicationContext applicationContext) {Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext);((AbstractApplicationContext) applicationContext).refresh();}
refreshContext会执行refresh方法
org/springframework/context/support/AbstractApplicationContext.java
public void refresh() throws BeansException, IllegalStateException {synchronized (this.startupShutdownMonitor) {// Prepare this context for refreshing.prepareRefresh();// Tell the subclass to refresh the internal bean factory.ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();// Prepare the bean factory for use in this context.prepareBeanFactory(beanFactory);try {// Allows post-processing of the bean factory in context subclasses.postProcessBeanFactory(beanFactory);// Invoke factory processors registered as beans in the context.invokeBeanFactoryPostProcessors(beanFactory);// Register bean processors that intercept bean creation.registerBeanPostProcessors(beanFactory);// Initialize message source for this context.initMessageSource();// Initialize event multicaster for this context.initApplicationEventMulticaster();// Initialize other special beans in specific context subclasses.onRefresh();// Check for listener beans and register them.registerListeners();// Instantiate all remaining (non-lazy-init) singletons.finishBeanFactoryInitialization(beanFactory);// Last step: publish corresponding event.finishRefresh();}catch (BeansException ex) {if (logger.isWarnEnabled()) {logger.warn("Exception encountered during context initialization - " +"cancelling refresh attempt: " + ex);}// Destroy already created singletons to avoid dangling resources.destroyBeans();// Reset 'active' flag.cancelRefresh(ex);// Propagate exception to caller.throw ex;}finally {// Reset common introspection caches in Spring's core, since we// might not ever need metadata for singleton beans anymore...resetCommonCaches();}}}
refresh先执行postProcessBeanFactory,比如添加BeanPostProcessors,之后执行invokeBeanFactoryPostProcessors,即执行BeanFactoryPostProcessor的postProcessBeanFactory方法
refresh执行完之后触发listeners.started(context)即发布ApplicationStartedEvent
执行完callRunners之后触发listeners.running(context)即发布ApplicationReadyEvent
handleRunFailure
private void handleRunFailure(ConfigurableApplicationContext context, Throwable exception,Collection<SpringBootExceptionReporter> exceptionReporters, SpringApplicationRunListeners listeners) {try {try {handleExitCode(context, exception);if (listeners != null) {listeners.failed(context, exception);}}finally {reportFailure(exceptionReporters, exception);if (context != null) {context.close();}}}catch (Exception ex) {logger.warn("Unable to close ApplicationContext", ex);}ReflectionUtils.rethrowRuntimeException(exception);}
触发listeners.failed(context, exception)即发布ApplicationFailedEvent
小结
SpringApplication的run方法,先触发listeners.starting()(ApplicationStartingEvent),然后执行了prepareEnvironment(ApplicationEnvironmentPreparedEvent),之后createApplicationContext,再进行prepareContext和refreshContext(ApplicationContextInitializedEvent–>ApplicationPreparedEvent),最后触发listeners.started(context)(ApplicationStartedEvent),之后执行callRunners,最后触发listeners.running(context)(ApplicationReadyEvent),期间有异常会执行handleRunFailure,触发listeners.failed(context, exception)(ApplicationFailedEvent)
其中refresh的时候会执行BeanFactoryPostProcessor的postProcessBeanFactory方法
整体顺序如下:ApplicationStartingEvent --> ApplicationEnvironmentPreparedEvent --> ApplicationContextInitializedEvent --> ApplicationPreparedEvent --> ApplicationStartedEvent --> ApplicationReadyEvent,期间有异常则抛出ApplicationFailedEvent
相关文章:
聊聊springboot的启动事件
序 本文主要研究一下springboot的启动事件 SpringApplicationEvent org/springframework/boot/context/event/SpringApplicationEvent.java public abstract class SpringApplicationEvent extends ApplicationEvent {private final String[] args;public SpringApplicatio…...
jmeter HTTP请求默认值
首先,打开JMeter并创建一个新的测试计划。 右键单击测试计划,选择"添加" > “配置元件” > “HTTP请求默认值”。 在HTTP请求默认值中,您可以设置全局的HTTP请求属性,例如: 服务器地址:…...
CSS选择器-CSS3属性
CSS选择器-CSS3属性 持续更新… 1、CSS3的概念和优势 css3概念:是css的升级版本,新增加了一些模块 css3优点:完全向后兼容,可使用新的选择器和属性,能实现新的设计效果CSS3是CSS技术的升级版本,CSS3语言开发是朝着模块化发展的。以前的规范作为一个模块实在是太庞…...
线性代数的学习和整理8:行列式相关
目录 1 从2元一次方程组求解说起 1.1 直接用方程组消元法求解 1.2 有没有其他方法呢?有:比如2阶行列式方法 1.3 3阶行列式 2 行列式的定义 2.1 矩阵里的方阵 2.2 行列式定义:返回值为标量的一个函数 2.3 行列式的计算公式 2.4 克拉…...
java+springboot+mysql农业园区管理系统
项目介绍: 使用javaspringbootmysql开发的农业园区管理系统,系统包含超级管理员、管理员、用户角色,功能如下: 超级管理员:管理员管理;用户管理;土地管理(租赁)&#x…...
IDEA远程开发
IDEA远程开发 前期准备 IDEA的远程开发是在本地去操昨远程服务器上的代码,所以我们先需要准备一台服务器,在此我使用vmware虚拟出ubuntu-20.04.6的Server版本,以便后面演示。 Ubuntu的Java环境配置 JDK8 sudo apt install openjdk-8-jdkmaven sudo apt instal…...
Redis 工作总结
1.Redis是什么 Redis是互联网技术领域使用最为广泛的存储中间件,它是Remote Dictionary Service的首字母缩写,也就是远程字典服务。 2.Redis的用途? 2.1 计数器 2.2 缓存 2.3 分布式锁 2.4 消息中间件 3.Redis的数据类型 3.1 string&am…...
GO学习之 数据库(Redis)
GO系列 1、GO学习之Hello World 2、GO学习之入门语法 3、GO学习之切片操作 4、GO学习之 Map 操作 5、GO学习之 结构体 操作 6、GO学习之 通道(Channel) 7、GO学习之 多线程(goroutine) 8、GO学习之 函数(Function) 9、GO学习之 接口(Interface) 10、GO学习之 网络通信(Net/Htt…...
谈一谈浏览器与Node.js中的JavaScript事件循环,宏任务与微任务机制
JavaScript中的异步代码 JavaScript是一个单线程非阻塞的脚本语言。这代表代码是执行在一个主线程上面的。但是JavaScript中有很多耗时的异步操作,例如AJAX,setTimeout等等;也有很多事件,例如用户触发的点击事件,鼠标…...
User Java bean的命名规范
Java Bean 是一种用于表示简单的、可重用的组件的规范。它是一个符合特定命名和约定的 Java 类,通常用于封装数据和提供访问方法。以下是关于 Java Bean 命名规范的一些准则: 类名: 类名应该使用驼峰命名法(Camel Case)…...
ajax和fetch的区别
ajax 和 fetch的相同点和区别是什么? 以前我们都用ajax去做请求, 但是原生的ajax不好用,我们会用$.ajax或者axios插件去请求,他们都是ajax的封装 最近出来个fetch是什么? 问到这里的时候,你就已经入坑了&am…...
java+springboot+mysql村务档案管理系统
项目介绍: 使用javaspringbootmysql开发的村务档案管理系统,系统包含超级管理员、工作人员角色,功能如下: 超级管理员:系统用户管理(工作人员管理);公开资料;会议记录&…...
windows查看/删除DNS缓存
一、查看DNS缓存 打开CMD,输入ipconfig/displaydns 二、删除DNS缓存 打开CMD,输入ipconfig/flushdns...
自动化测试之Junit
Junit引入注解参数化单参数多参数方法传参 测试用例执行顺序断言测试套件 Junit引入 Junit来编写和组织自动化测试用例,使用Selenium来实际模拟用户与Web应用程序的交互。也就是使用JUnit的测试功能来管理和运行Selenium测试。常见的做法是,使用JUnit作…...
Spring Boot 整合MyBatis-Plus
😀前言 本篇博文是关于Spring Boot 整合MyBatis-Plus的,希望你能够喜欢😊 🏠个人主页:晨犀主页 🧑个人简介:大家好,我是晨犀,希望我的文章可以帮助到大家,您的…...
CC++ 常用技巧
C 中的C C 是面向过程的是把整个大程序分为一个个的子函数;C 是面向对象的是把整个程序划分为一个个的类。C 是完全兼容C 的,C 是C 的子集,C 是C 的超集。C 又对C 做了很多补充和提升,因此使用C 会比使用纯C 更方便。混用C和C&am…...
【AndroidStudio】屏蔽小米打印
使用小米手机调试时,会一直有notifyQueue load error的打印 在过滤器重添加过滤条件即可 -message:notifyQueue...
Tomcat的安装与介绍
首先我们先了解一下什么是服务器?什么是服务器软件? 什么是服务器?安装了服务器软件的计算机。 什么是服务器软件? 服务器软件是一种运行在服务器操作系统上,用于接收和处理客户端请求,并提供相应服务和资…...
说点大实话丨知名技术博主 Kirito 测评云原生网关
作者:徐靖峰 关注了阿里云云原生公众号,经常能看到 MSE-Higress 相关的推文,恰逢这次阿里云产品举办了一个 MSE-Higress 云原生网关的测评活动,借此机会体验了一把云原生网关的功能。 购买流程体验 购买网关时,页面明…...
时序预测 | MATLAB实现SO-CNN-BiLSTM蛇群算法优化卷积双向长短期记忆神经网络时间序列预测
时序预测 | MATLAB实现SO-CNN-BiLSTM蛇群算法优化卷积双向长短期记忆神经网络时间序列预测 目录 时序预测 | MATLAB实现SO-CNN-BiLSTM蛇群算法优化卷积双向长短期记忆神经网络时间序列预测预测效果基本介绍程序设计参考资料 预测效果 基本介绍 时序预测 | MATLAB实现SO-CNN-BiL…...
多自由度冗余空间机械臂位姿一体化规划与控制【附代码】
✨ 长期致力于空间机械臂、对偶四元数、位姿一体化、路径规划、跟踪控制研究工作,擅长数据搜集与处理、建模仿真、程序编写、仿真设计。 ✅ 专业定制毕设、代码 ✅ 如需沟通交流,点击《获取方式》 (1)基于对偶四元数的冗余机械臂运…...
DeepSeek RAG系统渗透测试全链路复现(含PoC代码与防御加固清单)
更多请点击: https://kaifayun.com 第一章:DeepSeek RAG系统渗透测试全链路复现概览 DeepSeek RAG系统作为面向企业级知识检索增强生成的典型架构,其安全边界不仅涵盖LLM服务层,更延伸至向量数据库、检索代理、提示工程网关及外部…...
Android 11开发避坑:为什么你的App获取的Wifi MAC地址总是变?手把手教你配置固定MAC
Android 11开发实战:彻底解决Wifi MAC地址随机化问题最近在开发一个设备管理系统时,遇到了一个棘手的问题:我们的App在Android 11设备上获取的Wifi MAC地址每次都不一样,导致基于MAC地址的设备识别功能完全失效。经过一周的深入研…...
诚信标签工厂端解决方案 适配俄标 CRPT 体系一体化技术方案
俄罗斯诚实标签依托 CRPT 体系执行强制管控,各类出口货品必须完成 Data Matrix 编码采集、格式转换、多层包装数据绑定,数据合规后方可通关流通。美妆食品、日化建材、玩具五金等品类包装形态差异较大,人工采集方式普遍存在识别精度不足、批量…...
【紧急预警】92%的DeepSeek测试用例生成失败源于这4个隐性配置缺陷——资深SDET连夜整理修复清单
更多请点击: https://codechina.net 第一章:DeepSeek测试用例生成的现状与危机本质 当前,DeepSeek系列大模型(如DeepSeek-Coder、DeepSeek-VL)在代码生成与理解任务中展现出强大能力,但其测试用例自动生成…...
从CTF题看RSA安全:为什么你的密钥不能‘共享素数’?
从CTF实战看RSA密钥安全:那些年我们踩过的坑 在网络安全竞赛和实际渗透测试中,RSA算法的错误实现方式往往成为突破的关键点。本文将通过典型CTF赛题案例,揭示五种常见RSA实现漏洞背后的数学原理和安全启示,帮助开发者在实际项目中…...
AI写的论文双率如何压到20%以下?这几款工具实测有效
毕业季、投稿季用AI写论文已经成为不少人的高效选择,但查重率飘红、AIGC疑似率超标两大问题,让很多人犯了难。2026年学术检测标准持续收紧,知网、维普及主流AIGC检测系统同步上线双检规则,两项指标均控制在20%以下才符合基本提交要…...
【DeepSeek架构评审功能深度解密】:20年架构师亲授3大避坑指南与5步落地 checklist
更多请点击: https://kaifayun.com 第一章:DeepSeek架构评审功能全景概览 DeepSeek架构评审功能是一套面向大模型系统设计与工程落地的自动化分析框架,聚焦于模型结构合理性、计算图优化潜力、内存访问模式、算子兼容性及部署约束等多维度评…...
CPU架构启发的智能仓储布局优化实践
1. 仓库布局优化的核心挑战与创新机遇在物流仓储领域,拣货环节通常占据运营成本的55%-65%,而其中约50%的时间消耗在无效行走路径上。传统矩形仓库布局虽然易于规划和施工,但其正交的通道设计导致拣货员需要频繁进行90度转向,这种&…...
保姆级教程:在Ubuntu上配置Frida环境,搞定Android App的IO重定向与签名绕过
在Ubuntu上构建Android逆向工程环境:Frida实战与IO重定向技术解析 对于习惯Linux环境的安全研究人员而言,Windows-centric的逆向工具链往往带来诸多不便。本文将系统性地介绍如何在Ubuntu上搭建完整的Android逆向环境,并深入探讨如何利用Frid…...
