ssssSpringBoot框架的原理是很复杂的,但又是简单的,因为他不是最底层的框架,而是由不同的框架组成的,主要分为以下几个部分:
ssss①. Spring原理【Spring注解】、ssss②. SpringMVC原理ssss③. 自动配置原理. ssss④. SpringBoot(启动)原理
ssss⑤. 第三方框架 …
SpringBoot启动过程
ssss我们以 “deBug” 方式来进行分析:
sdsdsdsadsddsdsasdass
sdsddsdsdsss
ssss【注】:我们发现SpringBoot启动主要由两部分组成:①、● 创建 SpringApplication ②、● 运行 SpringApplication,接下来我们分别分析这两个方法
● 创建 SpringApplication
asdasdss
ssss ①、 保存一些信息。eg: 自定义环境、加载器等。
ssss ②、通过断言机制,如果当前传入的类为空,则直接终端运行,并回复"PrimarySources must not be null"
ssss ③、将传入类的相关信息存储起来,数据结构是 “LinkedHashSet”
sdasdasdsdasdss
ssss ④、 判定当前应用的类型。使用的工具式:ClassUtils,最终返回Servlet
ssdsdsddsddsdss
ssss ⑤、去spring.factories
找 ApplicationContextInitializer初始化器和ApplicationListener监听器。
ssss【注1】:我们将找到的监听器等分别存储到了ArrayList中,并且spring.factories
指的是导入的所有包中的spring.factories
,比如下面是其中的一个包中spring.factories
:
ssss【注2】:在之前版本的SpringBoot,还会寻找 bootstrappers:初始启动引导器(List< Bootstrapper >):去spring.factories文件中找org.springframework.boot.Bootstrapper
,但是在2.5版本没有。
ssss ⑥、在堆栈中找“main()”方法然后存储起来,比如当前的main方法: class com.atguigu.webadmin.Boot05WebAdminApplication
.
ssdsdsddsdsdsdsdsdsdsdsdss
● 运行 SpringApplication----->Run()方法
ssasdass
ssss● 运行 SpringApplication,即run()方法:
sssdsadas ①. StopWatchsss【注】:创建一个StopWach实例,为了后续记录时间
sssdsadas ②. 记录应用的启动时间 stopWatch.start();
sssdsadas【注】:在早写的SpringBoot版本,在这之后还创建引导上下文(Context环境)createBootstrapContext(),获取所有之前的 bootstrappers 挨个执行 intitialize() 来完成对引导启动器上下文环境设置。
sssdsadas ③. 让当前应用进入headless模式。java.awt.headless
sssdsadas【注】:headless模式是缺少显示设备,键盘或鼠标的系统配置。 听起来很意外,但实际上您可以在此模式下执行不同的操作,即使使用图形数据也是可以的。
sssdsadas ④. 获取所有 RunListener(运行监听器)【为了方便所有Listener进行事件感知】,然后遍历它们执行 starting() 方法:
sssdsadas【注】:getSpringFactoriesInstances 去spring.factories找 SpringApplicationRunListener.
sssdsadas【注】: starting():相当于通知所有感兴趣系统正在启动过程的人,项目正在 starting。
sssdsadas ⑤. 保存命令行参数;ApplicationArguments
sssdsadas ⑥. 准备环境 prepareEnvironment();
ssdsdssds
sssdsadsaddas ■ 返回或者创建基础环境信息对象,返回是StandardServletEnvironment
sssdsadsaddas ■ 配置环境信息对象。
sssdsadsdsdsaddas ● 读取所有的配置源的配置属性值。
sssdsadsaddas ■ 监听器调用 listener.environmentPrepared();通知所有的监听器当前环境准备完成
sssdsadsaddas ■ 绑定环境信息
sssdsadas【注】:在这之后还会配置一些忽略的信息,并且通过banner显示图标.
ssdsdsdsdsdsdsdsddssddssdssds
sssdsadas ⑦. 创建IOC容器(createApplicationContext())
sssdsadsaddas ■ 根据项目类型(Servlet)创建容器,
sssdsadsaddas ■ 当前会创建 AnnotationConfigServletWebServerApplicationContext
sssdsadas【注】:在这之后会获得异常报告。
sssdsadas ⑧. 准备ApplicationContext IOC容器的基本信息 prepareContext()
ssdsddssdsadsd
sssdsadsaddas ■ 保存环境信息
sssdsadsaddas ■ IOC容器的后置处理流程。
sssdsadsaddas ■ 应用初始化器;applyInitializers;
sssdsadsdsdsaddas ● 遍历所有的 ApplicationContextInitializer 。调用 initialize.。来对IOC容器进行初始化扩展功能
sssdsddsdsad
sssdsadsdsdsaddas ● 遍历所有的 listener 调用 contextPrepared。EventPublishRunListenr;通知所有的监听器contextPrepared
sssdsdsddsdssddsdsad
sssdsadsaddas ■ 所有的监听器 调用 contextLoaded。通知所有的监听器 contextLoaded;
sssdsadas⑨. 刷新IOC容器。refreshContext。容器刷新完成后再进行相关工作afterRefresh,不过看源码什么也没有,应该是给人们写的。
sdsdsdsdsddssssds
sssdsddas ■ 初始化web服务器,比如Tomcat等(但开启是在注册完所有组件之后),创建容器中的所有组件(Spring注解)。
sssdsadas ⑩. 获取运行的时间。stopWatch.stop();
sssdsadas ⒒. 所有监听器调用 listeners.started(context); 通知所有的监听器 started
sssdsadas12. 调用所有runners;callRunners()
sssdssdsdadas
sssdsadsaddas ■ 获取容器中的 ApplicationRunner
sssdsadsaddas ■ 获取容器中的 CommandLineRunner
sssdsadsaddas ■ 合并所有runner并且按照@Order进行排序
sssdsadsaddas ■ 遍历所有的runner。调用 run 方法
sssdsadas 13. 调用所有监听器的 running 方法 listeners.running(context); 通知所有的监听器 running
sssdsadas 14. 如果以上有异常,
sssdsadsaddas ■ 调用Listener 的 failed
sssdsadsddsas【注】:running如果有问题。继续通知 failed 。调用所有 Listener 的 failed;通知所有的监听器 failed
SpringBoot启动过程
ssss我们大致了解了SpringBoot启动过程后,就可以自定义一些组件,然后加载到SpringBoot的启动过程中。对应官方文档地址:https://docs.spring.io/spring-boot/docs/current/reference/html/features.html#features.spring-application.application-events-and-listeners
ssss自定义:ApplicationContextInitializer初始化器,ApplicationListener,SpringApplicationRunListener监听器
ssss自定义:ApplicationRunner 与 CommandLineRunner 可以让我们做一些一次性事情。