前言
此系列是针对springboot的启动,旨在于和大家一起来看看springboot启动的过程中到底做了一些什么事。如果大家对springboot的源码有所研究,可以挑些自己感兴趣或者对自己有帮助的看;但是如果大家没有研究过springboot的源码,不知道springboot在启动过程中做了些什么,那么我建议大家从头开始一篇一篇按顺序读该系列,不至于从中途插入,看的有些懵懂。当然,文中讲的不对的地方也欢迎大家指出,有待改善的地方也希望大家不吝赐教。老规矩:一周至少一更,中途会不定期的更新一些其他的博客,可能是springboot的源码,也可能是其他的源码解析,也有可能是其他的。
路漫漫其修远兮,吾将上下而求索!
github:https://github.com/youzhibing
码云(gitee):https://gitee.com/youzhibing
前情回顾
大家还记得上篇博文讲了什么吗,或者说大家知道上篇博文讲了什么吗。这里帮大家做个简单回顾:
创建web应用上下文,对其部分属性:reader、scanner、beanFactory进行了实例化;reader中实例化了属性conditionEvaluator;scanner中添加了两个AnnotationTypeFilter:一个针对@Component,一个针对@ManagedBean;beanFactory中注册了8个注解配置处理器的Bean。应用上下文类型实际上是AnnotationConfigServletWebServerApplicationContext,beanFactory的类型是DefaultListableBeanFactory,这两个类型的类图大家重点看下,既是上篇博文的重点,也是接下来系列博客的基点。创建上下文的过程其实还创建了environment,本文中会涉及到environment,大家请留意。
通过createApplicationContext方法之后,context的包含的主要内容如下:

prepareContext
先欣赏下我们的战绩,看看我们对run方法完成了多少的源码解读
View Code前菜
exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,new Class[] { ConfigurableApplicationContext.class }, context);
getSpringFactoriesInstances这个方法在
SpringBootExceptionReporter是一个回调接口,用于支持对SpringApplication启动错误的自定义报告。
先根据SpringBootExceptionReporter获取FailureAnalyzers的全限定类名,实例化FailureAnalyzers的时候,再次调用SpringFactoriesLoader.loadFactoryNames方法获取类型为FailureAnalyzer的名称列表,然后再根据名称列表实例化bean列表。
bean列表创建好之后,设置bean列表中满足条件的bean的beanFactory和environment,同时也将部分bean应用到context的environment和beanFactory中,代码如下
View Code其中NoSuchBeanDefinitionFailureAnalyer bean的setBeanFactory方法
View Code往beanFactory中注册一个名叫autoConfigurationReport的单例bean(类型是ConditionEvaluationReport),这个bean用于后面自动配置条件评估的详情报告与日志记录。
exceptionReporters 获取成功后,我们来看看beanFactory的变化

正餐
prepareContext内容不多,源代码如下
View Code我们逐个方法来看
context.setEnvironment(environment)
View Code将context中相关的environment全部替换成SpringApplication中创建的environment。还记得这篇中的疑问吗,引申下就是:之前我们的应用中有两个environment,一个在context中,一个在SpringApplication中。经过此方法后,就只会存在SpringApplication中的environment了,而context中的原environment会被回收。
postProcessApplicationContext(context);
View Code上下文后处理。SpringApplication子类可以根据需要应用其他处理。
由于当前SpringApplication实例的属性:beanNameGenerator和resourceLoader都为null,所以此方法目前相当于什么也没做。此方法可能是我们定制SpringApplication所用。
applyInitializers(context);
View Code在context refresh之前应用ApplicationContextInitializer到context中。还记得SpringApplication的属性initializers吗,不记得的可以点
一共6个initializer,他们的initialize方法都被调用,源代码就不跟了,上图中已经进行了展示,我们总结下
DelegatingApplicationContextInitializer
environment没有context.initializer.classes配置项,所以相当于没有做任何事。
如果配置了context.initializer.classes,获取其值(逗号分隔的initializer列表字符串),转换成class列表,根据classes列表进行实例化获取initializer实例列表,再对每个initializer实例调用initialize方法。
DelegatingApplicationContextInitializer相当于context.initializer.classes的代理,最终还是会执行到被代理的initializer的initialize方法。
Contex
