概述
用过Spring Boot
的应该都知道,在项目启动入口的主类main()
方法里,一句简简单单的SpringApplication.run( ... );
就可以成功启动项目了。
![image-20230209175528705](https://img-blog.csdnimg.cn/img_convert/83e3398c62f895951aff885ea4ddac81.png)
那么本文我们就来看看这个 SpringApplication 以及 run() 方法 到底是个什么鬼,它背后又隐藏了哪些奥秘呢?
SpringApplication对象的实例过程
具体的实例化代码如下
![image-20230209175955904](https://img-blog.csdnimg.cn/img_convert/5d39d49cc0665f2b14e11cd754e505fb.png)
其中实例化重要的四个步骤如上图标注,作用分别如下:
- 推断应用的类型:创建的是REACTIVE应用、SERVLET应用、NONE 三种中的某一种
![image-20230212131507738](https://img-blog.csdnimg.cn/img_convert/f8d78543294a44954eae3e53d4cb3e8f.png)
-
使用
SpringFactoriesLoader
查找并加载classpath下META-INF/spring.factories
文件中所有可用的ApplicationContextInitializer
-
使用
SpringFactoriesLoader
查找并加载classpath下META-INF/spring.factories
文件中的所有可用的ApplicationListener
-
推断并设置
main
方法的定义类
![image-20230213092415714](https://img-blog.csdnimg.cn/img_convert/e9923b1575976246d701453c939a5388.png)
SpringApplication的run方法探秘
具体代码如下图
![image-20230213092738941](https://img-blog.csdnimg.cn/img_convert/cce2604c59da699dfa0f4b5bd8b65663.png)
对应的流程图如下:
![image-20230213095109941](https://img-blog.csdnimg.cn/img_convert/1936fdef7078125e75c9a8faebd30847.png)
我们将各步骤总结精炼如下:
- 通过
SpringFactoriesLoader
加载META-INF/spring.factories
文件,获取并创建SpringApplicationRunListener
对象 - 然后由
SpringApplicationRunListener
来发出starting
消息 - 创建参数,并配置当前
SpringBoot
应用将要使用的Environment
- 完成之后,依然由
SpringApplicationRunListener
来发出environmentPrepared
消息 - 创建
ApplicationContext
- 初始化
ApplicationContext
,并设置Environment
,加载相关配置等 - 由
SpringApplicationRunListener
来发出contextPrepared
消息,告知Spring Boot 应用使用的ApplicationContext
已准备OK - 将各种
beans
装载入ApplicationContext
,继续由SpringApplicationRunListener
来发出contextLoaded
消息,告知 Spring Boot 应用使用的ApplicationContext
已装填OK refresh ApplicationContext
,完成IoC容器可用的最后一步- 由
SpringApplicationRunListener
来发出started
消息 - 调用
callRunners(...)
方法,让实现了ApplicationRunner
和CommandLineRunner
接口类的run
方法得以执行,用于在 Spring 应用上下文准备完毕后,执行一些额外操作。从而完成最终的程序的启动。 - 由
SpringApplicationRunListener
来发出running
消息,告知程序已运行起来了
至此,全流程结束。