springboot启动过程_不要搞笑哈,你用了5年的SpringBoot框架,竟然不了解它的启动过程?...
SpringBoot的启动很简单,代码如下:
从代码上可以看出,调用了SpringApplication的静态方法run。这个run方法会构造一个SpringApplication的实例,然后再调用这里实例的run方法就表示启动SpringBoot。
因此,想要分析SpringBoot的启动过程,我们需要熟悉SpringApplication的构造过程以及SpringApplication的run方法执行过程即可。
我们以上述这段代码为例,分析SpringBoot的启动过程。
# SpringApplication的构造过程
SpringApplication构造的时候内部会调用一个private方法initialize:
ApplicationContextInitializer,应用程序初始化器,做一些初始化的工作:
ApplicationListener,应用程序事件(ApplicationEvent)监听器:
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener { void onApplicationEvent(E event);}
应用程序事件监听器跟监听事件是绑定的。比如ConfigServerBootstrapApplicationListener只跟ApplicationEnvironmentPreparedEvent事件绑定,LiquibaseServiceLocatorApplicationListener只跟ApplicationStartedEvent事件绑定,LoggingApplicationListener跟所有事件绑定等。
默认情况下,initialize方法从spring.factories文件中找出的key为ApplicationContextInitializer的类有:
org.springframework.boot.context.config.DelegatingApplicationContextInitializer
org.springframework.boot.context.ContextIdApplicationContextInitializer
org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer
org.springframework.boot.context.web.ServerPortInfoApplicationContextInitializer
org.springframework.boot.autoconfigure.logging.AutoConfigurationReportLoggingInitializer
key为ApplicationListener的有:
org.springframework.boot.context.config.ConfigFileApplicationListener
org.springframework.boot.context.config.AnsiOutputApplicationListener
org.springframework.boot.logging.LoggingApplicationListener
org.springframework.boot.logging.ClasspathLoggingApplicationListener
org.springframework.boot.autoconfigure.BackgroundPreinitializer
org.springframework.boot.context.config.DelegatingApplicationListener
org.springframework.boot.builder.ParentContextCloserApplicationListener
org.springframework.boot.context.FileEncodingApplicationListener
org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener
# SpringApplication的执行
分析run方法之前,先看一下SpringApplication中的一些事件和监听器概念。
首先是SpringApplicationRunListeners类和SpringApplicationRunListener类的介绍。
SpringApplicationRunListeners内部持有SpringApplicationRunListener集合和1个Log日志类。用于SpringApplicationRunListener监听器的批量执行。
SpringApplicationRunListener看名字也知道用于监听SpringApplication的run方法的执行。
它定义了5个步骤:
started(run方法执行的时候立马执行;对应事件的类型是ApplicationStartedEvent)
environmentPrepared(ApplicationContext创建之前并且环境信息准备好的时候调用;对应事件的类型是ApplicationEnvironmentPreparedEvent)
contextPrepared(ApplicationContext创建好并且在source加载之前调用一次;没有具体的对应事件)
contextLoaded(ApplicationContext创建并加载之后并在refresh之前调用;对应事件的类型是ApplicationPreparedEvent)
finished(run方法结束之前调用;对应事件的类型是ApplicationReadyEvent或ApplicationFailedEvent)
SpringApplicationRunListener目前只有一个实现类EventPublishingRunListener,它把监听的过程封装成了SpringApplicationEvent事件并让内部属性(属性名为multicaster)ApplicationEventMulticaster接口的实现类SimpleApplicationEventMulticaster广播出去,广播出去的事件对象会被SpringApplication中的listeners属性进行处理。
所以说SpringApplicationRunListener和ApplicationListener之间的关系是通过ApplicationEventMulticaster广播出去的SpringApplicationEvent所联系起来的。
SpringApplication的run方法代码如下:
创建容器的方法createAndRefreshContext如下:
Spring容器的创建createApplicationContext方法如下:
Spring容器创建之后有个回调方法postProcessApplicationContext:
初始化器做的工作,比如ContextIdApplicationContextInitializer会设置应用程序的id;AutoConfigurationReportLoggingInitializer会给应用程序添加一个条件注解解析器报告等:
Spring容器的刷新refresh方法内部会做很多很多的事情:比如BeanFactory的设置,BeanFactoryPostProcessor接口的执行、BeanPostProcessor接口的执行、自动化配置类的解析、条件注解的解析、国际化的初始化等等。这部分内容会在之后的文章中进行讲解。
run方法中的Spring容器创建完成之后会调用afterRefresh方法,代码如下:
这样run方法执行完成之后。Spring容器也已经初始化完成,各种监听器和初始化器也做了相应的工作。
# 总结
SpringBoot启动的时候,不论调用什么方法,都会构造一个SpringApplication的实例,然后调用这个实例的run方法,这样就表示启动SpringBoot。
在run方法调用之前,也就是构造SpringApplication的时候会进行初始化的工作,初始化的时候会做以下几件事:
把参数sources设置到SpringApplication属性中,这个sources可以是任何类型的参数。本文的例子中这个sources就是MyApplication的class对象
判断是否是web程序,并设置到webEnvironment这个boolean属性中
找出所有的初始化器,默认有5个,设置到initializers属性中
找出所有的应用程序监听器,默认有9个,设置到listeners属性中
找出运行的主类(main class)
SpringApplication构造完成之后调用run方法,启动SpringApplication,run方法执行的时候会做以下几件事:
构造一个StopWatch,观察SpringApplication的执行
找出所有的SpringApplicationRunListener并封装到SpringApplicationRunListeners中,用于监听run方法的执行。监听的过程中会封装成事件并广播出去让初始化过程中产生的应用程序监听器进行监听
构造Spring容器(ApplicationContext),并返回
3.1 创建Spring容器的判断是否是web环境,是的话构造AnnotationConfigEmbeddedWebApplicationContext,否则构造AnnotationConfigApplicationContext
3.2 初始化过程中产生的初始化器在这个时候开始工作
3.3 Spring容器的刷新(完成bean的解析、各种processor接口的执行、条件注解的解析等等)从Spring容器中找出ApplicationRunner和CommandLineRunner接口的实现类并排序后依次执行
# 例子
写了一个例子用来验证分析的启动逻辑,包括自定义的初始化器、监听器、ApplicationRunner和CommandLineRunner。
源码地址:https://github.com/fangjian0423/springboot-analysis/tree/master/springboot-startup
作者:fangjian0423来源:http://fangjian0423.github.io/2017/04/30/springboot-startup-analysis/
往期推荐
?
- 项目一上线,遇到内存泄漏,排查坑哭了我...
- 太赞了,IDEA 2020开始为不懂English的程序员服务了...
- Ordered接口在Spring中的意义是什么?
点击
springboot启动过程_不要搞笑哈,你用了5年的SpringBoot框架,竟然不了解它的启动过程?...相关推荐
- springboot 不响应字段为空_面试官扎心一问:Tomcat 在 SpringBoot 中是如何启动的?...
作者:木木匠 http://my.oschina.net/luozhou/blog/3088908 前言 我们知道 SpringBoot 给我们带来了一个全新的开发体验,我们可以直接把 web 程序达 ...
- rhel系统启动过程_技术|Linux 开机引导和启动过程详解
你是否曾经对操作系统为何能够执行应用程序而感到疑惑?那么本文将为你揭开操作系统引导与启动的面纱. 理解操作系统开机引导和启动过程对于配置操作系统和解决相关启动问题是至关重要的.该文章陈述了 GRUB2 ...
- uefi启动linux过程_【转载】简述Linux的启动过程
本文将简单介绍一下Linux的启动过程,希望对那些安装Linux的过程中遇到了问题的朋友有些帮助 声明:本人没用过UEFI模式和GPT分区格式,所有关于这两部分的内容都是网络上找的资料,仅供参考. 典 ...
- springboot启动图标_自定义 SpringBoot 启动Logo
Solomon_肖哥弹架构 跟大家"弹弹" SpringBoot 的整体设计方案与核心功能点,那么今天来看自定义SpringBoot如何自定义启动Logo. 欢迎 点赞,点赞,点赞 ...
- 命令 启动顺序_笔记一: 启动选项与系统变量
启动选项(startup options) 定义: MySQL有很多设置项,如存储引擎,客户端连接数量,缓存大小等,这些设置项在配置文件中都有默认值,在启动MySQL时可以在启动命令后面加一些参数来修 ...
- ai无法启动产品_启动AI启动的三个关键教训
ai无法启动产品 重点 (Top highlight) Let me be upfront: I was the technical co-founder of an AI startup and i ...
- ubuntu 安装Pangolin 过程_余辉亮的学习笔记的博客-CSDN博客_pangolin安装
ubuntu 安装Pangolin 过程_余辉亮的学习笔记的博客-CSDN博客_pangolin安装
- 无人驾驶运动学模型——线性时变模型预测控制的思路推演过程_百叶书的博客-CSDN博客_线性时变模型预测控制 转
无人驾驶运动学模型--线性时变模型预测控制的思路推演过程_百叶书的博客-CSDN博客_线性时变模型预测控制
- java bat 启动脚本_解析Tomcat的启动脚本--catalina.bat
概述 Tomcat 的三个最重要的启动脚本: startup.bat catalina.bat setclasspath.bat 上一篇咱们分析了 startup.bat 脚本 这一篇咱们来分析 ca ...
最新文章
- php创建多级目录完整封装类操作
- 一系列用于Fuzzing学习的资源汇总
- docker-macvlan网络
- 客户端页面不更新CSS样式或JS脚本的方法 (2018-08-17 17:33)
- 《高性能MySQL(第3版)》摘要——索引篇
- 4 QM配置-质量计划配置-编辑缺陷类型的代码组和代码
- phpcms关于 {if} 判断后台是否上传{thumb} 缩略图 - 代码篇
- Zookeeper的默认选举
- 微服务升级_SpringCloud Alibaba工作笔记0019---Nacos之服务配置中心
- ormlite更改数据库默认位置
- 使用 ngrok(小米球)实现内网穿透映像到外网访问项目
- VB6 用ODBC连接数据库
- linux编译gdal geos,GDAL编译支持GEOS
- win10新建计算机账户,Windows10系统创建microsoft帐户的方法
- 开源是不是程序员悲剧的根源?
- MySQL多表事务(三)
- C语言system讲解
- 2022年高处安装、维护、拆除培训试题模拟考试平台操作
- 数控开料机,板式家具开料机
- 最近常常干出一些骑着驴找驴的事来
热门文章
- 年终凡尔赛,都是别人家的公司...
- 抛出运行时异常的目的_「JAVA」运行时异常、编译时异常、自定义异常,通过案例实践转译和异常链...
- SpringBoot定义统一的controller返回格式
- php使用webuploader表单上传文件覆盖文件key doesn't match with scope的问题和解决思路
- cannot import name ‘compare_ssim‘
- CenterNet2:比强更强的二阶段网络,COCO成绩最高达到56.4mPA
- yolov5 soft_nms cluster_nms,cluster_SPM_nms,cluster_diounms,cluster_SPM_dist_nms,diou_nms
- js MediaSource h264
- opengl嵌入pyqt5编译的分割窗口中
- libcusolver.so.8.0: cannot open shared object file: No such file or director