SpringBoot启动原理详解

透彻理解SpringBoot启动原理(一)

  • 一张Spring启动顺序图
    • 我们对Spring启动原理有多少理解呢
    • 一起看一下Spring有那些扩展点和启动过程有关
    • 通过打印日志学习Spring的执行顺序
    • 实例化和初始化的区别
    • Spring重要扩展点的启动顺序
        • 1.BeanFactoryPostProcessor
        • 2.实例化Bean
        • 3.Autowired装配依赖
        • 4.BeanNameAware
        • 5.BeanFactoryAware
        • 6.ApplicationConextAware setApplicationContext
        • 7.BeanPostProcessor postProcessBeforeInitialization
        • 8.PostConstruct 执行
        • 9.InitializingBean
        • 10.init-method
        • 11.BeanPostProcessor postProcessAfterInitialization
        • 12.其他Bean 实例化和初始化
        • 13.所有单例Bean 初始化完成后
        • 14.SmartInitializingSingleton Bean实例化后置处理
        • 15.Spring 提供的扩展点,在所有单例Bean的 EventListener等组件全部启动完成后,即Spring启动完成,则执行 start 方法。在这个位置适合开启入口流量!
        • 16.发布 ContextRefreshedEvent 方法
        • 17.注册和初始化 Spring MVC
        • 18.Tomcat/Jetty 容器开启端口
        • 19.应用启动完成后,执行 CommandLineRunner

一张Spring启动顺序图

Hellow! 我们一起看一下这张 Spring启动顺序图 在这里插入图片描述

我们对Spring启动原理有多少理解呢

我在这里为大家准备了一些很细节但贯穿整个spring启动流程的常见问题:

  1. Spring常见的流量入口有哪些?
  2. SpringBoot集成Tomcat,如果Http流量先进入了,此时Spring还未启动完成,怎么办?那Tomcat是何时开启端口对外服务的呢?
  3. Spring集成RPC框架,RPC框架何时注册暴露服务,在Spring那个扩展点注册呢?
  4. Spring集成MQ消费组,MQ消费者何时开始消费,在Spring那个扩展点“注册消费者”?
  5. Spring还未完全启动,在 PostConstruct 中调用 getBeanByAnnotation 能否获得准确的结果?;
  6. 项目应该如何监听 Spring 的启动就绪事件?项目如何监听Spring 刷新事件?
  7. Spring就绪事件和刷新事件的执行顺序和区别?
  8. Http 流量入口何时启动完成?
  9. PostConstruct 中方法依赖ApplicationContextAware拿到 ApplicationContext,两者的顺序谁先谁后?是否会出现空指针!
  10. init-method、PostConstruct、afterPropertiesSet 三个方法的执行顺序?
    如上10个问题,作为在Spring框架中苦苦挣扎的你,能理解并解答出几个呢?

一起看一下Spring有那些扩展点和启动过程有关

BeanFactoryAware 可在Bean 中获取BeanFactory 实例
ApplicationContextAware 可在Bean 中获取ApplicationContext 实例
BeanNameAware 可以在Bean中得到它在IOC容器中的Bean的实例的名字。
ApplicationListener 可监听ContextRefreshedEvent
CommandLineRunner 整个项目启动完毕后,自动执行
SmartLifecycle#start在Spring Bean实例化完成后,执行start 方法。
使用@PostConstruct注解,用于Bean实例初始化
实现InitializingBean接口,用于Bean实例初始化
xml中声明init-method方法,用于Bean实例初始化
Configuration 配置类 通过@Bean注解 注册Bean到Spring
BeanPostProcessor 在Bean的初始化前后,植入扩展点!
BeanFactoryPostProcessor BeanFactory 创建后植入扩展点

通过打印日志学习Spring的执行顺序

我们通过代码实验,验证一下以上扩展点的执行顺序
1.声明TestSpringOrder分别集成以下接口,并在接口方法中实现,日志打印该接口名称。

public class TestSpringOrder implementsApplicationContextAware,BeanFactoryAware, InitializingBean, SmartLifecycle, BeanNameAware, ApplicationListener<ContextRefreshedEvent>, CommandLineRunner,SmartInitializingSingleton {
@Override
public void afterPropertiesSet() throws Exception {log.error("启动顺序:afterPropertiesSet");
}@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {log.error("启动顺序:setApplicationContext");
}

2.TestSpringOrder使用PostConstruct注解初始化,声明init-method方法初始化

@PostConstruct
public void postConstruct() {log.error("启动顺序:post-construct");
}public void initMethod() {log.error("启动顺序:init-method");
}

3.新建TestSpringOrder2继承

public class TestSpringOrder3 implementsBeanPostProcessor, BeanFactoryPostProcessor {@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {log.error("启动顺序:BeanPostProcessor postProcessBeforeInitialization beanName:{}", beanName);return bean;}@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {log.error("启动顺序:BeanPostProcessor postProcessAfterInitialization beanName:{}", beanName);return bean;}@Overridepublic void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {log.error("启动顺序:BeanFactoryPostProcessor postProcessBeanFactory ");}
}

执行以上代码后,可以在日志中看到启动顺序!

2023-11-25 18:10:53,748 [main] ERROR (TestSpringOrder3:37) - 启动顺序:BeanFactoryPostProcessor postProcessBeanFactory 
2023-11-25 18:10:59,299 [main] ERROR (TestSpringOrder:53) - 启动顺序:构造函数 TestSpringOrder
2023-11-25 18:10:59,316 [main] ERROR (TestSpringOrder:127) - 启动顺序: Autowired
2023-11-25 18:10:59,316 [main] ERROR (TestSpringOrder:129) - 启动顺序:setBeanName
2023-11-25 18:10:59,316 [main] ERROR (TestSpringOrder:111) - 启动顺序:setBeanFactory
2023-11-25 18:10:59,316 [main] ERROR (TestSpringOrder:121) - 启动顺序:setApplicationContext
2023-11-25 18:10:59,316 [main] ERROR (TestSpringOrder3:25) - 启动顺序:BeanPostProcessor postProcessBeforeInitialization beanName:testSpringOrder
2023-11-25 18:10:59,316 [main] ERROR (TestSpringOrder:63) - 启动顺序:post-construct
2023-11-25 18:10:59,317 [main] ERROR (TestSpringOrder:116) - 启动顺序:afterPropertiesSet
2023-11-25 18:10:59,317 [main] ERROR (TestSpringOrder:46) - 启动顺序:init-method
2023-11-25 18:10:59,320 [main] ERROR (TestSpringOrder3:31) - 启动顺序:BeanPostProcessor postProcessAfterInitialization beanName:testSpringOrder
2023-11-25 18:17:21,563 [main] ERROR (SpringOrderConfiguartion:21) - 启动顺序: @Bean 注解方法执行
2023-11-25 18:17:21,668 [main] ERROR (TestSpringOrder:58) - 启动顺序:SmartInitializingSingleton
2023-11-25 18:17:21,675 [main] ERROR (TestSpringOrder:74) - 启动顺序:start
2023-11-25 18:17:23,508 [main] ERROR (TestSpringOrder:68) - 启动顺序:ContextRefreshedEvent
2023-11-25 18:17:23,574 [main] ERROR (TestSpringOrder:79) - 启动顺序:CommandLineRunner

实例化和初始化的区别

new TestSpringOrder():new 创建对象实例,即为实例化一个对象;执行该Bean的 init-method 等方法 为初始化一个Bean。注意初始化和实例化的区别

Spring重要扩展点的启动顺序

1.BeanFactoryPostProcessor

BeanFactory初始化之后,所有的Bean定义已经被加载,但Bean实例还没被创建(不包括BeanFactoryPostProcessor类型)。Spring IoC容器允许BeanFactoryPostProcessor读取配置元数据,修改bean的定义,Bean的属性值等。

2.实例化Bean

Spring 调用java反射API 实例化 Bean。等同于 new TestSpringOrder();

3.Autowired装配依赖

Autowired是 借助于 AutowiredAnnotationBeanPostProcessor 解析 Bean 的依赖,装配依赖。如果被依赖的Bean还未初始化,则先初始化 被依赖的Bean。在 Bean实例化完成后,Spring将首先装配Bean依赖的属性。

4.BeanNameAware

setBeanName();

5.BeanFactoryAware

setBeanFactory();

6.ApplicationConextAware setApplicationContext

在Bean实例化前,会率先设置Aware接口,例如 BeanNameAware BeanFactoryAware ApplicationContextAware 等

7.BeanPostProcessor postProcessBeforeInitialization

如果我想在 bean初始化方法前后要添加一些自己逻辑处理。可以提供 BeanPostProcessor接口实现类,然后注册到Spring IoC容器中。在此接口中,可以创建Bean的代理,甚至替换这个Bean。

8.PostConstruct 执行

接下来 Spring会依次调用 Bean实例初始化的 三大方法。

9.InitializingBean

afterPropertiesSet();

10.init-method

方法执行

11.BeanPostProcessor postProcessAfterInitialization

在 Spring 对Bean的初始化方法执行完成后,执行该方法

12.其他Bean 实例化和初始化

Spring 会循环初始化Bean。直至所有的单例Bean都完成初始化

13.所有单例Bean 初始化完成后
14.SmartInitializingSingleton Bean实例化后置处理

该接口的执行时机在 所有的单例Bean执行完成后。例如Spring 事件订阅机制的 EventListener注解,所有的订阅者 都是 在这个位置被注册进 Spring的。而在此之前,Spring Event订阅机制还未初始化完成。所以如果有 MQ、Rpc 入口流量在此之前开启,Spring Event就可能出问题!

所以强烈建议 Http、MQ、Rpc 入口流量在 SmartInitializingSingleton 之后开启流量。

Http、MQ、Rpc 入口流量必须在 SmartInitializingSingleton 之后开启流量!

15.Spring 提供的扩展点,在所有单例Bean的 EventListener等组件全部启动完成后,即Spring启动完成,则执行 start 方法。在这个位置适合开启入口流量!

Http、MQ、Rpc 入口流量适合 在 SmartLifecyle 中开启

16.发布 ContextRefreshedEvent 方法

该事件会执行多次,在 Spring Refresh 执行完成后,就会发布该事件!

17.注册和初始化 Spring MVC

SpringBoot 应用,在父级 Spring启动完成后,会尝试启动 内嵌式 tomcat容器。在此之前,SpringBoot会初始化 SpringMVC 和注册DispatcherServlet到Web容器。

18.Tomcat/Jetty 容器开启端口

SpringBoot 调用内嵌式容器,会开启并监听端口,此时Http流量就开启了。

19.应用启动完成后,执行 CommandLineRunner

SpringBoot 特有的机制,待所有的完全执行完成后,会执行该接口 run方法。值得一提的是,由于此时Http流量已经开启,如果此时进行本地缓存初始化、预热缓存等,稍微有些晚了!在这个间隔期,可能缓存还未就绪!
所以预热缓存的时机应该发生在 入口流量开启之前,比较合适的机会是在 Bean初始化的阶段。虽然 在Bean初始化时 Spring尚未完成启动,但是调用 Bean预热缓存也是可以的。但是注意:不要在 Bean初始化时 使用 Spring Event,因为它还未完成初始化 。

此篇讲解启动顺序,关于启动原理问题的解答请见 透彻理解Springboot启动原理(二)

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

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

相关文章

python3.10.4——Windows环境安装

python下载官网&#xff1a;https://www.python.org/downloads/ 如果安装在C盘&#xff0c;需要右键→选择“以管理员身份运行” 勾选2个按钮&#xff0c;选择自定义安装 全部选择&#xff0c;点击Next 更改安装路径 命令行检查python是否安装成功&#xff1a; 出现版本号说明…

内存泄漏详解

文章目录 什么是内存泄漏内存泄漏的原因排查及解决内存泄漏避免内存泄漏及时释放资源设置合理的变量作用域及时清理不需要的对象避免无限增长避免内部类持有外部类引用使用弱引用 什么是内存泄漏 内存泄漏是指不使用的对象持续占有内存使得内存得不到释放&#xff0c;从而造成…

【Hot100】LeetCode—416. 分割等和子集

目录 题目1- 思路2- 实现⭐152. 乘积最大子数组——题解思路 3- ACM 实现 题目 原题连接&#xff1a;416. 分割等和子集 1- 思路 理解为背包问题 思路&#xff1a; 能否将均分的子集理解为一个背包&#xff0c;比如对于 [1,5,11,5]&#xff0c;判断能否凑齐背包为 11 的容量…

面试场景题系列--(1)如果系统的 QPS 突然提升 10 倍该怎么设计?--xunznux

1. 如果系统的 QPS 突然提升 10 倍该怎么设计&#xff1f; 1.1 硬件的扩展微服务的拆分 如果所有的业务包括交易系统、会员信息、库存、商品等等都夹杂在一起&#xff0c;当流量一旦起来之后&#xff0c;单体架构的问题就暴露出来了&#xff0c;机器挂了所有的业务就全部无法…

SSCI 二区正刊 绿色金融、财政、经济、债务、成本、创新题目:

1金融科技能提升企业的双元创新能力吗&#xff1f;组织韧性xxxxx 2从财政分权到经济高质量发展&#xff1a;税收征管强度xxxxxxx 3企业智能化转型、债务融资成本与绿色xxxx 绿色金融改革能否促进地方经济高质量发展&#xff1a;基于绿色金融改革创新试验区的准xxxx 4绿色金融改…

MBR60200PT-ASEMI无人机专用MBR60200PT

编辑&#xff1a;ll MBR60200PT-ASEMI无人机专用MBR60200PT 型号&#xff1a;MBR60200PT 品牌&#xff1a;ASEMI 封装&#xff1a;TO-247 批号&#xff1a;最新 恢复时间&#xff1a;35ns 最大平均正向电流&#xff08;IF&#xff09;&#xff1a;60A 最大循环峰值反向…

win11 安装 Gradle

一、win11 安装Gradle(7.5.1)&#xff1a; 1.1、下载二进制包 Gradle下载页面 1.2、配置环境变量 变量名&#xff1a;GRADLE_HOME 变量值&#xff08;二进制包解压路径&#xff09;&#xff1a;D:\develop-tool\gradle-7.5.1 变量名&#xff1a;GRADLE_USER_HOME 变量值&a…

JAVA基础 - 控制语句

目录 一. 简介 二. 分支语句 三. 循环语句 四. 跳转语句 一. 简介 在 Java 中&#xff0c;控制语句用于控制程序的执行流程&#xff0c;根据不同的条件决定执行哪些代码块。常见的控制语句包括&#xff1a; if-else 语句&#xff1a;根据条件的真假执行不同的代码块。 swi…

Spark实时(一):StructuredStreaming 介绍

文章目录 StructuredStreaming 介绍 一、SparkStreaming实时数据处理痛点 1、复杂的编程模式 2、SparkStreaming处理实时数据只支持Processing Time 3、微批处理&#xff0c;延迟高 4、精准消费一次问题 二、StructuredStreaming概述 三、​​​​​​​​​​​​​​…

BGP选路之AS-PATH

原理概述 当一台BGP路由器中存在多条去往同一目标网络的BGP路由时&#xff0c;BGP协议会对这些BGP路由的属性进行比较&#xff0c;以确定去往该目标网络的最优BGP路由。首先要比较的属性是 Preferred Value&#xff0c;然后是Local Preference&#xff0c;再次是路由生成方式&a…

算法学习笔记:回溯法

回溯法有“通用的解题法”之称。用它可以系统地搜索一个问题的所有解或任一解。回溯法是一个既带有系统性又带有跳跃性的搜索算法。它在包含问题的所有解的解空间树中&#xff0c;按照深度优先的策略&#xff0c;从根节点出发搜索解空间树。算法搜索至解空间树的任一节点时&…

【Android Studio】整合okhttp发送get和post请求(提供Gitee源码)

前言&#xff1a;本篇博客教学大家如何使用okhttp发送同步/异步get请求和同步/异步post请求&#xff0c;这边博主把代码全部亲自测试过了一遍&#xff0c;需要源码的可以在文章最后自行拉取。 目录 一、导入依赖 二、开启外网访问权限 三、发送请求 3.1、发送同步get请求…

关于pycharm上push项目到gitee失败原因

版权声明&#xff1a;本文为博主原创文章&#xff0c;如需转载请贴上原博文链接&#xff1a;https://blog.csdn.net/u011628215/article/details/140577821?spm1001.2014.3001.5502 前言&#xff1a;最近新建项目push上gitee都没有问题&#xff0c;但是当在gitee网站进行了一个…

2024在线PHP加密网站源码

源码介绍 2024在线PHP加密网站源码 更新内容: 1.加强算法强度 2.优化模版UI 加密后的代码示例截图 源码下载 https://download.csdn.net/download/huayula/89568335

kafka集群搭建-使用zookeeper

1.环境准备&#xff1a; 使用如下3台主机搭建zookeeper集群&#xff0c;由于默认的9092客户端连接端口不在本次使用的云服务器开放端口范围内&#xff0c;故端口改为了8093。 172.2.1.69:8093 172.2.1.70:8093 172.2.1.71:8093 2.下载地址 去官网下载&#xff0c;或者使用如…

Mysql的主从复制(重要)和读写分离(理论重要实验不重要)

一、主从复制&#xff1a;架构一般是一主两从。 1.主从复制的模式&#xff1a; mysql默认模式为异步模式&#xff1a;主库在更新完事务之后会立即把结果返回给从服务器&#xff0c;并不关心从库是否接收到以及从库是否处理成功。缺点&#xff1a;网络问题没有同步、防火墙的等…

vue3-video-play 导入 以及解决报错

npm install vue3-video-play --save # 或者 yarn add vue3-video-play import Vue3VideoPlay from vue3-video-play; import vue3-video-play/dist/style.css; app.use(Vue3VideoPlay) <template><div id"main-container-part"><div class"al…

Meta发布最强AI模型,扎克伯格公开信解释为何支持开源?

凤凰网科技讯 北京时间7月24日&#xff0c;脸书母公司Meta周二发布了最新大语言模型Llama 3.1&#xff0c;这是该公司目前为止推出的最强大开源模型&#xff0c;号称能够比肩OpenAI等公司的私有大模型。与此同时&#xff0c;Meta CEO马克扎克伯格(Mark Zuckerberg)发表公开信&a…

opencv grabCut前景后景分割去除背景

参考&#xff1a; https://zhuanlan.zhihu.com/p/523954762 https://docs.opencv.org/3.4/d8/d83/tutorial_py_grabcut.html 环境本次&#xff1a; python 3.10 提取前景&#xff1a; 1、需要先把前景物体框出来 需要坐标信息&#xff0c;可以用windows自带的画图简单提取像素…

Concat() Function-SQL-字符串拼接函数

Concat() Function-SQL 在SQL中&#xff0c;CONCAT() 函数用于将两个或多个字符串连接在一起。 不同数据库管理系统可能有些许差异&#xff0c;但基本用法和语法通常是相似的。 语法 CONCAT(string1, string2, ...)string1, string2, …: 这些是需要连接的字符串参数。可以…