初识SpringApplication运行原理
- 准备阶段
- 配置Spring Bean的来源
默认我们配置的路径就是classpath:
- 推断:web类型
Web类型推断的实现:
①判断webApplicationType 是web Flux类型并且不是Servlet类型,则返回web Flux类型。否则进行下一步。
②判断webApplicationType 如果是no web类型,返回NONE。否则 返回Servlet类型 。
注意:如果我们的web flux 与 Servlet都配置了,那么Spring会判定该web类型是Servlet。 当然我们的Web类型的Spring也 可 以通过Application.WebApplicationType = WebApplicationType.NONE设置为no web 类型。
- 加载:应用上下文初始化
应用上下文初始化其实就是一些关于ApplicationContext的初始化参数,需要在启动之前进行加载,因此以这种方式进行加 载。
加载方式:
①实现类:SpringFactoriesLoader
②配置资源:META-INF --> spring.factories
③排序:@Order()或者实现Order接口(一般的注解都能使用接口实现方式来替代)
自定义ApplicationContextInitializer
①实现类:
① @Order(Ordered.HIGHEST_PRECEDENCE) ② @Order(Ordered.LOWEST_PRECEDENCE) |
②配置资源
运行结果:
细心的能看出来,我们实现接口的时候上面有我们的排序注解,排序的顺序就是我们控制台上打印出来的顺序。
- 加载:应用监听器
监听器的加载机制和我们ApplicationContextInitializer的加载机制是一样,只不过实现的接口不一样而已。
自定义监听器:
①实现我们的ApplicationListener并且注解排序
@Order(Ordered.HIGHEST_PRECEDENCE) |
配置资源
@Order(Ordered.LOWEST_PRECEDENCE) |
运行结果:
- 推断:main的主类
通过异常堆栈的方式将我们拥有main方法的堆栈元素找到,再获取该堆栈的ClassName,则此类为主类。
- 运行阶段
从源码可以看出基本上可以分为以下几个步骤:
- 加载:SpringApplication运行监听器 getRunListeners(args)
加载出SpringApplicationRunListeners类,该类控制我们监听器的生命周期。
2.运行:SpringApplication运行监听器 starting(listeners)
将我们的SpringApplicationRunListener的实现类都一一启动。
3.监听:Spring Boot事件、Spring事件
该类启动之后,会将我们Spring中的Listener都启动,开始监听模式:
- 创建:应用上下文、Environment、其他(不是很重要)
- 失败:故障分析报表
看名称就知道每一步是做什么的。里面有应用上下文、Environment、故障分析报表、其他(不是很重要)。
注意:细心的同学可以看出,我们的prepareContext()方法是用来加载配置资源的。
- 回调:CommandLineRunner、ApplicationRunner
最后进行我们的回调
CommandLineRunner、ApplicationRunner用来对我们Bean的排序工作,比如我们监听器的排序工作。
自定义实现ApplicationContextRunListener
①实现我们SpringApplicationRunListener 接口,此处没有进行排序。
public class FirstHelloWorldRunListener implements SpringApplicationRunListener { //这一步必须有,否则报错 |
②配置资源
运行结果:
可以看出RunListener监听器比我们banner还要早,那是因为run方法中,starting比banner早一步。
上篇文章遗留问题:
ApplicationContext什么时候加载我们@Configuration?
我们每一个启动类中都有@SpringBootApplication注解,注解里面扫描了它下面所有的文件夹。