简介

        分析Spring的启动流程有多种方法:1.构造一个 AnnotationConfigApplicationContext对象,调用它的getBean(xxx.class)方法; 2.直接分析SpringBoot的启动流程。

        本文直接分析SpringBoot的启动流程。本文分析的版本:SpringBoot版本:2.3.0.RELEASE(其对应Spring:5.2.6.RELEASE)。

总流程概述

简介

  1. 从spring.factories配置文件中加载EventPublishingRunListener对象
    该对象有SimpleApplicationEventMulticaster属性,它在SpringBoot启动过程的不同阶段用来发射内置的生命周期事件;
    spring.factories位置:spring-boot-2.3.0.RELEASE.jar。
        本处用到的是:
           org.springframework.boot.SpringApplicationRunListener=\
           org.springframework.boot.context.event.EventPublishingRunListener
  2. 准备环境变量(Environment)
    包括系统变量,环境变量,命令行参数,默认变量,servlet相关配置变量,随机值以及配置文件(比如application.properties)等;
  3. 打印SpringBoot的bannner标志
  4. 根据不同类型环境创建不同类型的ApplicationContext容器
    因为这里是servlet环境,所以创建的是AnnotationConfigServletWebServerApplicationContext容器对象;
  5. 加载报告SpringBoot启动过程中的异常的对象​;
    从spring.factories配置文件中加载FailureAnalyzers对象,
  6. 为刚创建的容器对象做一些初始化工作,准备一些容器属性值​等;

    对ApplicationContext调用一些相关的后置处理调用各个ApplicationContextInitializer的初始化方法来执行一些初始化逻辑等;

  7. 刷新容器。​这一步至关重要。

    调用BeanFactoryPostProcessor(bean factory的后置处理器())注册BeanPostProcessor(bean后置处理器)初始化事件广播器、发布事件初始化剩下的单例bean。(调用到BeanPostProcessor)SpringBoot创建内嵌的Tomcat服务器

  8. 执行​刷新容器后的后置处理​逻辑,注意这里为空方法;
  9. 调用​ApplicationRunner和CommandLineRunner的run方法
    我们实现这两个接口可以在Spring容器启动后执行一些操作
  10. 报告启动异常
    若启动过程中抛出异常,此时用FailureAnalyzers来报告异常;
  11. 最终返回容器对象,这里调用方法没有声明对象来接收。

源码分析

SpringApplication.run(DemoApplication.class, args);    //DemoApplication.class

    run(new Class[]{primarySource}, args);                         //SpringApplication.class

        (new SpringApplication(primarySources)).run(args);    //SpringApplication.class

                public ConfigurableApplicationContext run(String... args) //SpringApplication.class

public ConfigurableApplicationContext run(String... args) {
// new 一个StopWatch用于统计run启动过程花了多少时间
StopWatch stopWatch = new StopWatch();
// 开始计时
stopWatch.start();

ConfigurableApplicationContext context = null;

// exceptionReporters集合存储异常报告器,用来报告SpringBoot启动过程的异常
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList();

// 配置“java.awt.headless”属性,默认true。即:即使没有检测到显示器,也允许其启动。
// 对于服务器来说,是不需要显示器的,所以要这样设置.
this.configureHeadlessProperty();

// 【1】从spring.factories文件中找出key为ApplicationContextInitializer的类并实例化,然后赋值
// 给SpringApplicationRunListeners。目前里边只有:EventPublishingRunListener,
// 它发射SpringBoot启动过程中内置的生命周期事件,标志不同启动阶段
SpringApplicationRunListeners listeners = this.getRunListeners(args);

//发布【ApplicationStartingEvent】事件。
listeners.starting();

Collection exceptionReporters;
try {
// 创建ApplicationArguments对象,封装了args参数
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);

// 【2】准备环境变量:系统变量,环境变量,命令行参数,默认变量,servlet相关配置变量,随机值,
// JNDI属性值,以及配置文件(比如application.properties)等,注意这些环境变量是有优先级的
// 发布【ApplicationEnvironmentPreparedEvent】事件
ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);

// 配置spring.beaninfo.ignore属性,默认为true,即跳过搜索BeanInfo classes.
this.configureIgnoreBeanInfo(environment);

// 【3】控制台打印SpringBoot的bannner标志
Banner printedBanner = this.printBanner(environment);

// 【4】创建不同类型的Spring ApplicationContext容器(根据类型)
// 这里我引入web包,所以创建的是AnnotationConfigServletWebServerApplicationContext容器对象
context = this.createApplicationContext();

// 【5】从spring.factories中加载异常报告期实例,这里加载的是FailureAnalyzers。
// FailureAnalyzers构造参数为ConfigurableApplicationContext,因为要获取beanFactory和environment
exceptionReporters = this.getSpringFactoriesInstances(SpringBootExceptionReporter.class,
new Class[]{ConfigurableApplicationContext.class}, context);

// 【6】为刚创建的容器对象做一些初始化工作,准备一些容器属性值等
// 1)为容器对象的属性AnnotatedBeanDefinitionReader和ClassPathBeanDefinitionScanner设置environgment属性
// 2)根据情况对ApplicationContext应用一些相关的后置处理,比如设置resourceLoader属性等
// 3)容器刷新前调用各个ApplicationContextInitializer的初始化方法,ApplicationContextInitializer是在
// 构建SpringApplication对象时从spring.factories中加载的
// 4)发布【ApplicationContextInitializedEvent】事件。标志context容器被创建且已准备好
// 5)从context容器获取beanFactory,向beanFactory中注册一些单例bean,比如applicationArguments,printedBanner
// 6)TODO 加载bean到application context,注意这里只是加载了部分bean比如mainApplication这个bean,
// 猜测:大部分bean是在AbstractApplicationContext.refresh方法中被加载
// 7)发布【ApplicationPreparedEvent】事件。标志Context容器已经准备完成
this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);

// 【7】刷新容器,这一步至关重要,主要做了以下工作:
// 1)在context刷新前做一些准备工作,比如初始化一些属性设置,属性合法性校验和保存容器中的一些早期事件等;
// 2)让子类刷新其内部bean factory,注意SpringBoot和Spring启动的情况执行逻辑不一样
// 3)对bean factory进行配置,比如配置bean factory的类加载器,后置处理器等
// 4)准备完bean factory后,执行后置处理逻辑,子类重写此方法在BeanFactory创建并预准备完成后做进一步设置
// 在这一步,所有的bean definitions将会被加载,但此时bean还不会被实例化
// 5)执行BeanFactoryPostProcessor的方法即调用bean factory的后置处理器:
// BeanDefinitionRegistryPostProcessor(触发时机:bean定义注册之前)
// BeanFactoryPostProcessor(触发时机:bean定义注册之后bean实例化之前)
// 6)注册bean后置处理器BeanPostProcessor。不同接口类型的BeanPostProcessor在Bean创建前后的执行时机不一样
// 7)初始化国际化MessageSource相关的组件,比如消息绑定,消息解析等
// 8)初始化事件广播器,若bean factory没包含事件广播器,
// 则new一个SimpleApplicationEventMulticaster广播器对象并注册到bean factory中
// 9)AbstractApplicationContext定义了一个模板方法onRefresh,留给子类覆写。
// 比如ServletWebServerApplicationContext覆写了该方法来创建内嵌的tomcat容器
// 10)注册ApplicationListener接口的实现类,之前已经有了事件广播器,此时即可发布early application events
// 11)完成容器bean factory的初始化,并初始化所有剩余的单例bean。
// 这一步非常重要,一些BeanPostProcessor会在这里调用。
// 12)完成容器的刷新工作,并且调用生命周期处理器的onRefresh()方法,并且发布ContextRefreshedEvent事件
this.refreshContext(context);

// 【8】执行刷新容器后的后置处理逻辑。目前这里为空方法
this.afterRefresh(context, applicationArguments);

// 停止stopWatch计时
stopWatch.stop();

// 打印日志
if (this.logStartupInfo) {
(new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
}

// 发布【ApplicationStartedEvent】事件。标志spring容器已经刷新,此时所有的bean实例都已经加载完毕
listeners.started(context);

// 【9】调用ApplicationRunner和CommandLineRunner的run方法。
this.callRunners(context, applicationArguments);
} catch (Throwable var10) {
// 【10】若启动过程中抛出异常,此时用FailureAnalyzers来报告异常
// 并发布【ApplicationFailedEvent】事件,标志SpringBoot启动失败
this.handleRunFailure(context, var10, exceptionReporters, listeners);
throw new IllegalStateException(var10);
}

try {
// 发布【ApplicationReadyEvent】事件。标志SpringApplication已在运行(即已经成功启动),可以接收服务请求了。
listeners.running(context);
// 【11】最终返回容器
return context;
} catch (Throwable var9) {
// 若出现异常,此时仅仅报告异常,而不会发射任何事件
this.handleRunFailure(context, var9, exceptionReporters, (SpringApplicationRunListeners)null);
throw new IllegalStateException(var9);
}
}

refresh()简述

在上边“总流程概述”中,this.refreshContext(context);是关键,追踪它:

this.refreshContext(context);  //SpringApplication.class

    this.refresh((ApplicationContext)context); // SpringApplication.class

        this.refresh((ConfigurableApplicationContext)applicationContext); //SpringApplication.class

            applicationContext.refresh(); // SpringApplication.class

                void refresh(); // ConfigurableApplicationContext.class(这是个接口)

                    void refresh(); // AbstractApplicationContext.class(这是个抽象类,实现了上边接口)

                        //下边是上边抽象类的两个子类,但它们都没覆写refresh(),只调用了抽象类的refresh()

                        final void refresh() // ServletWebServerApplicationContext.class

                        final void refresh() // ReactiveWebServerApplicationContext.class

所以,我们只需关注于:AbstractApplicationContext#refresh()

@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
//容器刷新前的准备:设置上下文状态,获取属性,验证必要的属性等
prepareRefresh();

// Tell the subclass to refresh the internal bean factory.
// 获取新的beanFactory,销毁原有beanFactory、为每个bean生成BeanDefinition等。
// 注意,此处是获取新的,销毁旧的,这就是刷新的意义
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

// Prepare the bean factory for use in this context.
// 配置beanFactory:设置BeanPostProcessor、ClassLoader,SpEL表达式解析器等
// BeanPostProcessor:ApplicationContextAwareProcessor和ApplicationListenerDetector
// 前者:它回调实现了ApplicationContextAware的类的setApplicationContext()方法,
// 后者:将ApplicationListener的实现类bean加入到监听器列表中
prepareBeanFactory(beanFactory);

try {
// Allows post-processing of the bean factory in context subclasses.
// 空方法,允许在子类中对beanFactory进行后置处理。
postProcessBeanFactory(beanFactory);

// Invoke factory processors registered as beans in the context.
// 实例化并调用所有注册的beanFactory后置处理器(实现接口BeanFactoryPostProcessor的bean)。
// 在beanFactory标准初始化之后执行 例如:PropertyPlaceholderConfigurer(处理占位符)
invokeBeanFactoryPostProcessors(beanFactory);

// Register bean processors that intercept bean creation.
// 注册BeanPostProcessor的实现类。
// 因为里面调用了getBean()方法,所以这一步实际也会将所有BeanPostProcessor实例化
// 例如:
// AutowiredAnnotationBeanPostProcessor(处理被@Autowired注解修饰的bean并注入)
// RequiredAnnotationBeanPostProcessor(处理被@Required注解修饰的方法)
// CommonAnnotationBeanPostProcessor(处理@PreDestroy、@PostConstruct、@Resource等多个注解的作用)等。
// 自定义的BeabPostProcessor
registerBeanPostProcessors(beanFactory);

// Initialize message source for this context.
// 初始化国际化工具类MessageSource
initMessageSource();

// Initialize event multicaster for this context.
// 初始化事件广播器
initApplicationEventMulticaster();

// Initialize other special beans in specific context subclasses.
// 模板方法,在容器刷新的时候可以自定义逻辑(子类自己去实现逻辑),不同的Spring容器做不同的事情
onRefresh();

// Check for listener beans and register them.
// 注册监听器,并且广播early application events,也就是早期的事件
registerListeners();

// Instantiate all remaining (non-lazy-init) singletons.
// 实例化所有剩余的(非懒加载)单例Bean。(也就是我们自己定义的那些Bean们)
// 比如invokeBeanFactoryPostProcessors方法中根据各种注解解析出来的类,在这时被初始化
// 为什么说是剩余呢?若开发人员自定义了BeanPosrProcessor,它在前面已实例化,所以这里不会再实例化
// 实例化时,各种BeanPostProcessor起作用
finishBeanFactoryInitialization(beanFactory);

// Last step: publish corresponding event.
// refresh做完之后需要做的其他事情
// 清除上下文资源缓存(如扫描中的ASM元数据)
// 初始化上下文的生命周期处理器,并刷新(找出Lifecycle接口的实现类(bean)并执行其onRefresh()方法。
// 发布ContextRefreshedEvent事件告知对应的ApplicationListener进行相应操作
finishRefresh();
} catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}

// Destroy already created singletons to avoid dangling resources.
//如果刷新失败那么就会将已经创建好的单例Bean销毁掉
destroyBeans();

// Reset 'active' flag.
//重置context的活动状态 告知是失败的
cancelRefresh(ex);

// Propagate exception to caller.
//抛出异常
throw ex;
} finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
// 失败与否,都会重置Spring内核的缓存。因为可能不再需要metadata给单例Bean了。
resetCommonCaches();
}
}
}

refresh()详述

AbstractApplicationContext#refresh()

在refresh()方法中,比较重要的方法为invokeBeanFactoryPostProcessors(beanFactory) 和 finishBeanFactoryInitialization(beanFactory)。其他方法都比较简单。 

prepareRefresh()

概述

容器刷新前的准备:设置上下文状态,获取属性,验证必要的属性等

位于:AbstractApplicationContext类

protected void prepareRefresh() {
//记录容器启动时间,然后设立对应的标志位
this.startupDate = System.currentTimeMillis();
this.closed.set(false);
this.active.set(true);

// 打印info日志:开始刷新this此容器了
if (logger.isInfoEnabled()) {
logger.info("Refreshing " + this);
}

// Initialize any placeholder property sources in the context environment
// 这是扩展方法,由子类去实现,可以在验证之前为系统属性设置一些值可以在子类中实现此方法
// 因为我们这边是AnnotationConfigApplicationContext,可以看到不管父类还是自己,都什么都没做,所以此处先忽略
initPropertySources();

// Validate that all properties marked as required are resolvable
// see ConfigurablePropertyResolver#setRequiredProperties
//这里有两步,getEnvironment(),然后是是验证是否系统环境中有RequiredProperties参数值 如下详情
// 然后管理Environment#validateRequiredProperties 后面在讲到环境的时候再专门讲解吧
// 这里其实就干了一件事,验证是否存在需要的属性
getEnvironment().validateRequiredProperties();

// Allow for the collection of early ApplicationEvents,
// to be published once the multicaster is available...
// 初始化容器,用于装载早期的一些事件
this.earlyApplicationEvents = new LinkedHashSet<>();
}

AbstractApplicationContext#getEnvironment()

getEnvironment()的顶层接口位于:EnvironmentCapable,有如下实现

SpringBoot原理--启动流程_spring boot

注意ConfigurableApplicationContext是接口,所以其实容器的实现只有AbstractApplicationContext

AbstractApplicationContext:上下文

ConfigurableApplicationContext:容器上下文

GenericFilterBean:Spring的过滤器

HttpServletBean:DispatcherServlet

obtainFreshBeanFactory()

概述

实际上就是重新创建一个bean工厂,并销毁原工厂。主要工作是创建DefaultListableBeanFactory实例,解析配置文件,注册Bean的定义信息。

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
refreshBeanFactory();
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if (logger.isDebugEnabled()) {
logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
}
return beanFactory;
}

refreshBeanFactory()是具体的刷新BeanFactory。即:AbstractRefreshableApplicationContext#refreshBeanFactory

@Override
protected final void refreshBeanFactory() throws BeansException {
// 判断是否已经存在BeanFactory,存在则销毁所有Beans,并且关闭BeanFactory
// 避免重复加载BeanFactory
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {
// 创建具体的beanFactory,这里创建的是DefaultListableBeanFactory,最重要的beanFactory spring注册及加载bean就靠它
// createBeanFactory()这个方法,看下面,还有得说的
DefaultListableBeanFactory beanFactory = createBeanFactory();
beanFactory.setSerializationId(getId());

// 这句比较简单,就是把当前旧容器的一些配置值复制给新容器
// allowBeanDefinitionOverriding属性是指是否允对一个名字相同但definition不同进行重新注册,默认是true。
// allowCircularReferences属性是指是否允许Bean之间循环引用,默认是true.
// 这两个属性值初始值为空:复写此方法即可customizeBeanFactory
customizeBeanFactory(beanFactory);

// 这个就是最重要的了,加载所有的Bean配置信息,具体如下详细解释
// 它属于模版方法,由子类去实现加载的方式
loadBeanDefinitions(beanFactory);
synchronized (this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}

createBeanFactory()

// 创建的时候就是new了一个工厂:DefaultListableBeanFactory   这个时候工厂里面所有东西都是默认值,很多还没有完成初始化属性的设置呢
protected DefaultListableBeanFactory createBeanFactory() {
return new DefaultListableBeanFactory(getInternalParentBeanFactory());
}

// 给设置父的BeanFactory,若存在的话
public AbstractAutowireCapableBeanFactory(@Nullable BeanFactory parentBeanFactory) {
this();
setParentBeanFactory(parentBeanFactory);
}

// 父类空构造器有这么些语句
public AbstractAutowireCapableBeanFactory() {
super();

// 这里是重点。忽略自动装配。这里指定的都是接口。什么意思呢?
// ignoreDependencyInterface的真正意思是在自动装配时忽略指定接口的实现类中,对外的依赖。(这里面注意:@Autowired和它的关系,其实是有坑的,后续会专门讲解这个坑)
ignoreDependencyInterface(BeanNameAware.class);
ignoreDependencyInterface(BeanFactoryAware.class);
ignoreDependencyInterface(BeanClassLoaderAware.class);
}

//找到父的,若存在就返回 若存在父容器就存在父的BeanFactory
@Nullable
protected BeanFactory getInternalParentBeanFactory() {
return (getParent() instanceof ConfigurableApplicationContext) ?
((ConfigurableApplicationContext) getParent()).getBeanFactory() : getParent();
}

AnnotationConfigWebApplicationContext#loadBeanDefinitions()方法,加载Bean的定义

@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) {
// 初始化这个脚手架 其实就是直接new出实例。具体做的工作,下面有相关博文链接
AnnotatedBeanDefinitionReader reader = getAnnotatedBeanDefinitionReader(beanFactory);
ClassPathBeanDefinitionScanner scanner = getClassPathBeanDefinitionScanner(beanFactory);

// 生成Bean的名称的生成器,如果自己没有setBeanNameGenerator(可以自定义),这里目前为null
BeanNameGenerator beanNameGenerator = getBeanNameGenerator();
if (beanNameGenerator != null) {
reader.setBeanNameGenerator(beanNameGenerator);
scanner.setBeanNameGenerator(beanNameGenerator);
//若我们注册了beanName生成器,那么就会注册进容器里面
beanFactory.registerSingleton(AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR, beanNameGenerator);
}

//这是给reader和scanner注册scope的解析器 此处为null
ScopeMetadataResolver scopeMetadataResolver = getScopeMetadataResolver();
if (scopeMetadataResolver != null) {
reader.setScopeMetadataResolver(scopeMetadataResolver);
scanner.setScopeMetadataResolver(scopeMetadataResolver);
}

// 此处注意了:annotatedClasses和basePackages一般是选其一(当然看到此处,他们是可以并存的)
//我们可以自己指定annotatedClasses 配置文件,同时也可以交给下面扫描
if (!this.annotatedClasses.isEmpty()) {

// 这里会把所有的配置文件输出=======info日志 请注意观察控制台
if (logger.isInfoEnabled()) {
logger.info("Registering annotated classes: [" +
StringUtils.collectionToCommaDelimitedString(this.annotatedClasses) + "]");
}

// 若是指明的Bean,就交给reader去处理,至于怎么处理,见上篇博文的doRegisterBean去怎么解析每一个Config Bean的
reader.register(ClassUtils.toClassArray(this.annotatedClasses));
}

// 也可以是包扫描的方式,扫描配置文件的Bean
if (!this.basePackages.isEmpty()) {
// 输出对应的info日志
if (logger.isInfoEnabled()) {
logger.info("Scanning base packages: [" +
StringUtils.collectionToCommaDelimitedString(this.basePackages) + "]");
}

// 这里重要了,scan方法具体做了什么事,上篇博文也有详细的介绍,请参阅
scanner.scan(StringUtils.toStringArray(this.basePackages));
}

// 此处的意思是,也可以以全类名的形式注册。比如可以调用setConfigLocations设置(这在xml配置中使用较多) 可以是全类名,也可以是包路径
String[] configLocations = getConfigLocations();
if (configLocations != null) {
for (String configLocation : configLocations) {
try {
Class<?> clazz = ClassUtils.forName(configLocation, getClassLoader());
reader.register(clazz);
} catch (ClassNotFoundException ex) {
// 发现不是全类名,那就当作包扫描吧
int count = scanner.scan(configLocation);
}
}
}
}

postProcessBeanFactory(beanFactory)

空方法,允许在子类中对beanFactory进行后置处理。

invokeBeanFactoryPostProcessors(beanFactory)

概述

        该方法的作用是执行所有的BeanFactoryPostProcessor,由于Spring会内置一个BeanFactoryPostProcessor,即ConfigurationClassPostProcessor(如果开发人员不自定义,默认情况下只有这一个BeanFactoryPostProcessor),这个后置处理器在处理时,会解析出所有交由Spring容器管理的Bean,将它们解析成BeanDefinition,然后放入到BeanFactory的BeanDefinitionMap中。

         该方法最终会调用到PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors()方法,主要作用是执行所有BeanFactoryPostProcessor的postProcessorBeanFactory()方法。BeanFactoryPostProcessor又分为两种情况,一种是直接实现BeanFactoryPostProcessor接口的类,另一种情况是实现了BeanDefinitionRegistryPostProcessor接口(BeanDefinitionRegistryPostProcessor继承了BeanFactoryPostProcessor接口)。

        在执行过程中先执行所有的BeanDefinitionRegistryPostProcessor的postProcessorBeanDefinitionRegistry()方法,然后再执行BeanFacotryPostProcessor的postProcessorBeanFactory()方法。

        默认情况下,Spring有一个内置的BeanFactoryPostProcessor,即:ConfigurationClassPostProcessor类,该类实现了BeanDefinitionRegistryPostProcessor类,所以会执行ConfigurationClassPostProcessor.postProcessorBeanDefinitionRegistry,ConfigurationClassPostProcessor的UML图如上(删减了部分不重要的继承关系)

registerBeanPostProcessors(beanFactory)

概述

        该方法的作用是找到所有的BeanPostProcessor,然后将这些BeanPostProcessor实例化(会调用getBean()方法,getBean()方法的主要逻辑是,如果bean存在于BeanFactory中,则返回bean;如果不存在,则会去创建。在后面会仔细分析getBean()的执行逻辑)。将这些PostProcessor实例化后,最后放入到BeanFactory的beanPostProcessors属性中。

        问题:如何找到所有的BeanPostProcessor? 包括Spring内置的和开发人员自定义的。

        由于在refresh()方法中,会先执行完invokeBeanFactoryPostProcessor()方法,这样所有自定义的BeanPostProcessor类均已经被扫描出并解析成BeanDefinition(扫描和解析又是谁做的呢?ConfigurationClassPostProcessor做的),存入至BeanFactory的BeanDefinitionMap,所以这儿能通过方法如下一行代码找出所有的BeanPostProcessor,然后通过getBean()全部实例化,最后再将实例化后的对象加入到BeanFactory的beanPostProcessors属性中,该属性是一个List集合。

        最后再重新注册了ApplicationListenerDetector,这样做的目的是为了将ApplicationListenerDetector放入到后置处理器的最末端

        registerBeanPostProcessor() 最终调用的是PostProcessorRegistrationDelegate.registerBeanPostProcessors(),下面是PostProcessorRegistrationDelegate.registerBeanPostProcessors()方法的代码。

        BeanPostProcessor存在优先级,实现了PriorityOrdered接口的优先级最高,其次是Ordered接口,最后是普通的BeanPostProcessor。优先级最高的,会最先放入到beanPostProcessors这个集合的最前面,这样在执行时,会最先执行优先级最高的后置处理器(因为List集合是有序的)。这样在实际应用中,如果我们碰到需要优先让某个BeanPostProcessor执行,则可以让其实现PriorityOrdered接口或者Ordered接口。

initMessageSource()

用来支持消息国际化,现在一般项目中不会用到国际化相关的知识。

initApplicationEventMulticaster()

概述

        该方法初始化了一个事件广播器,如果容器中存在了beanName为applicationEventMulticaster的广播器,则使用该广播器;如果没有,则初始化一个SimpleApplicationEventMulticaster。该事件广播器是用来做应用事件分发的,这个类会持有所有的事件监听器(ApplicationListener),当有ApplicationEvent事件发布时,该事件监听器能根据事件类型,检索到对该事件感兴趣的ApplicationListener。

源码

protected void initApplicationEventMulticaster() {
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
// 判断spring容器中是否已经存在beanName = applicationEventMulticaster的事件广播器
// 例如:如果开发人员自己注册了一个
// 如果存在,则使用已经存在的;否则使用spring默认的:SimpleApplicationEventMulticaster
if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
this.applicationEventMulticaster =
beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
}
else {
this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
}
}

onRefresh()

概述

执行其他的初始化操作,例如和SpringMVC整合时,需要初始化一些其他的bean。对于纯Spring工程来说,onRefresh()方法是一个空方法。

 如果我们整合了SpringMVC,它会启动一个TomcatServer这个服务器。

源码

 如果我们整合了SpringMVC,则其其最终覆写方法为:ServletWebServerApplicationContext#onRefresh()

protected void onRefresh() {
super.onRefresh();

try {
this.createWebServer();
} catch (Throwable var2) {
throw new ApplicationContextException("Unable to start web server", var2);
}
}
private void createWebServer() {
WebServer webServer = this.webServer;
ServletContext servletContext = this.getServletContext();
if (webServer == null && servletContext == null) {
ServletWebServerFactory factory = this.getWebServerFactory();
this.webServer = factory.getWebServer(new ServletContextInitializer[]{this.getSelfInitializer()});
this.getBeanFactory().registerSingleton("webServerGracefulShutdown", new WebServerGracefulShutdownLifecycle(this.webServer));
this.getBeanFactory().registerSingleton("webServerStartStop", new WebServerStartStopLifecycle(this, this.webServer));
} else if (servletContext != null) {
try {
this.getSelfInitializer().onStartup(servletContext);
} catch (ServletException var4) {
throw new ApplicationContextException("Cannot initialize servlet context", var4);
}
}

this.initPropertySources();
}

registerListeners()

概述

        将自定义的listener的bean名称放入到事件广播器中,同时还会将早期的ApplicationEvent发布(对于单独的Spring工程来说,在此时不会有任何ApplicationEvent发布,但是和SpringMVC整合时,SpringMVC会执行onRefresh()方法,在这里会发布事件)。

源码

protected void registerListeners() {
// Register statically specified listeners first.
for (ApplicationListener<?> listener : getApplicationListeners()) {
getApplicationEventMulticaster().addApplicationListener(listener);
}

// 从BeanFactory中找到所有ApplicationListener,但不初始化,因为要在后面bean实例化的过程中,让所有的BeanPostProcessor去改造它们
String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
for (String listenerBeanName : listenerBeanNames) {
// 将事件监听器的beanName放入到事件广播器中
getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
}

// 发布早期的事件(纯的spring工程,在此时一个事件都没有)
Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
this.earlyApplicationEvents = null;
if (earlyEventsToProcess != null) {
for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
getApplicationEventMulticaster().multicastEvent(earlyEvent);
}
}
}

finishBeanFactoryInitialization(beanFactory)

概述

该方法十分重要,它完成了所有非懒加载的单例Bean的实例化和初始化,属性的填充以及解决了循环依赖等问题。

详述

finishRefresh()

概述

清除上下文资源缓存(如扫描中的ASM元数据)

初始化上下文的生命周期处理器,并刷新(找出Lifecycle接口的实现类(bean)并执行其onRefresh()方法。

发布ContextRefreshedEvent事件告知对应的ApplicationListener进行相应操作

代码

protected void finishRefresh() {
this.clearResourceCaches();
this.initLifecycleProcessor();
this.getLifecycleProcessor().onRefresh();
this.publishEvent((ApplicationEvent)(new ContextRefreshedEvent(this)));
LiveBeansView.registerApplicationContext(this);
}

resetCommonCaches()

概述

在前面创建bean时,对单例bean的元数据信息进行了缓存,而单例bean在容器启动后,不会再进行创建了,因此这些缓存的信息已经没有任何用处了,在这里进行清空,释放部分内存。

代码

protected void resetCommonCaches() {
ReflectionUtils.clearCache();
AnnotationUtils.clearCache();
ResolvableType.clearCache();
CachedIntrospectionResults.clearClassLoader(this.getClassLoader());
}

 其他网址

​SpringBoot应用启动过程分析 - 知乎​

​SpringBoot的启动流程是怎样的?SpringBoot源码(七)​

​Spring源码系列之容器启动流程​

​SpringBoot 应用程序启动过程探秘​