首先需要一个加了@SpringBootApplication注解的启动类,这个注解由@EnableAutoConfiguration,@SpringBootConfiguration,@ComponentScan
@EnableAutoConfiguration是最核心的,有了它之后在启动时就会导入“自动配置”AutoConfigurationImportSelector类,这个类会将所有符合条件的@Configruation配置进行加载
@SpringBootConfiguration相当于@Configuration,就是将这个类标记为配置类加载到容器中
@ComponentScan是自动扫描并加载符合条件的bean
如果启动类中不需要添加配置内容,也不需要扫描路径,那可以使用@EnableAutoConfiguration来代替@SpringBootApplication也可以完成启动,注解完成后,SpringBoot运行的起点就是**SpringApplication.run()**方法;
服务启动会经过四个阶段:服务构建 环境准备 容器创建 填充容器
构建SpringApplication,首先要把传入的“资源加载器,主方法类”记录在内存中,然后逐一判断对应的服务类是否存在,来确定web服务的类型(默认是servlet:基于SERVLET的web服务)
确定了选择哪个web服务后就要加载初始化类了,读取所有的META-INF/spring.factories文件中的“注册初始化”,“上下文初始化”,“监听器”这三类配置
接下来通过“运行栈”stackTrace判断出main方法所在的类,大概率就是启动类本身
接下来就是调用它的run方法进入到环境准备阶段
这个阶段的目的是为了给即将诞生的容器提供充足的“养分”准备
1.首先会创建一个后续会陆续使用到的“启动上下文”BootStrapContext“
同时逐一调用刚刚加载的“启动注册初始化器”BootStrapRegistryInitializer中的初始化方法initialize方法,但由于默认并没有BootStrapRegistryInitializer,所以默认并不执行什么
2.接下调用configureHeadlessProperty()方法将“java.awt.headless”设置为true,表示缺少显示器,键盘等输入设备也能正常启动
3.然后启动体内的运行监听器SpringApplicationRunListeners,同时发布启动事件,它获取并加载spring-boot工程,spring factories配置文件中的EvenPublishingRunListen,并且在启动时也会将我们刚刚所说的默认的8个ApplicationListen全部进行引入,这样就可以通过监听这些事件在启动流程中加入自定义的逻辑
4.接下来通过prepareEnvironment方法组装启动参数
1)首先就是构造一个可配置的环境,根据不同的web类型会创建不同的环境,同样默认是servlet
2)构造后会加载很多诸如“系统环境变量”systemEnvironment,“JVM系统属性”等,systemProperties等在内的四种配置信息,把这些配置信息都加载到propertySources的内存集合中,这样后续使用就不需要再重新加载了
3)这时也会通过“配置环境”configureEnvironment将我们启动时传入的环境参数args进行设置,同时在propertySources集合的首个位置添加一个值为空的配置内容“configurationProperties”后续会被使用
4)接下来会发布环境准备完成这个事件,刚加载进来的8个监听器会监听找到这个事件,其中的监听器会进行相应的处理,诸如环境后配置处理监听器EnvironmentPostProcessorApplicationListener会加载spring.factories配置文件中的“环境配置后处理器”EnvironmentPostProcessor,这里注意监听器通过观察者模式设计,是逐一串行执行,并不是异步并行,需要等待所有的监听器都处理完成之后才会继续后续的逻辑
5)接下来将环境进行绑定
6)刚创建的可配置环境在一系列过程中可能会有变化进而做的补偿,通过二次更新保证匹配
5.紧接着将spring.beaninfo.ignore设为true,表示不加载bean的元数据信息,同时打印我的bannert图,这样环境准备阶段就完成了
所谓容器,就是指内部有很多属性,集合以及配套功能的结构体ApplicationContext,也可以称为“上下文”
通过createApplicationContext来创建容器,创建过程很简单
首先根据服务类型创建容器“ConfigurableApplicationContext”,默认的服务类型是servlet,所以创建的是注解配置的servlet-web服务容器
把它们都放入容器后就要调用prepareContext方法对容器内的部分属性进行初始化
1.先用postProcessApplicationContext方法设置“bean名称生成器”,“资源加载器”,“类型转换器”等
2.接着就要执行我们刚刚加载进来的“上下文初始化”ApplicationContextinitializerl了,默认加载了7个,容器ID,警告日志处理,监听日志都是在这里实现的
3.发布容器准备完成监听事件之后陆续为容器注册“启动参数”,“banner”,“bean引用策略”,“懒加载策略”
4.之后通过bean定义加载器将“启动类”在内的资源加载到bean定义池BeanDefinitionMap中,以便后续根据bean定义创建bean对象
5.然后发布一个资源加载完成事件
在这一步中会生产我自身提供的以及定义的所有的bean对象,并且放在刚刚创建的容器内部,这个过程也被称为“自动装配”
发布“启动完成”事件的同时回调自定义实现的Runner接口,来处理一些执行后定制化需求
至此spring boot的启动流程就结束了