- 通过
SpringApplication
开始引导启动 new SpringApplication
——创建引导启动的实例run()
——开始引导启动new StopWatch()
——创建计时器configureHeadlessProperty()
——配置Headless模式SpringApplicationRunListener.start()
——获取监听器,启动监听prepareEnvironment()
——准备环境,创建ConfigurableEnvironment
对象printBanner()
——打印横幅createApplicationContext()
——创建应用程序上下文并加载BeanprepareContext()
——准备ApplicationContext
refreshContext()
——刷新上下文prepareRefresh()
——准备刷新prepareBeanFactory()
——准备BeanFactory
postProcessBeanFactory()
——后置处理BeanFactory
invokeBeanFactoryPostProcessors()
——实例化并调用BeanFactoryPostProcessor
registerBeanPostProcessors()
——注册Bean后置处理器initMessageSource()
——初始化MessageSource
initApplicationEventMulticaster()
——初始化ApplicationEventMulticaster
onRefresh()
——刷新应用程序registerListeners()
——注册监听器finishBeanFactoryInitialzation()
——初始化容器中的BeanfinishRefresh()
——完成刷新
afterRefresh()
——留给子类的钩子函数- 启动完成
- 准备运行
- 总结
通过SpringApplication
开始引导启动
SpringApplication
类是用来执行Spring框架启动的引导类。有两种方式可以进行启动引导:
- 通过静态方法
SpringApplication.run
启动。 - 先创建
SpringApplication
实例,在调用的实例方法run
进行启动。
无论是以上哪种方式,最终都是通过创建SpringApplication
实例,在调用run()
启动。
new SpringApplication
——创建引导启动的实例
在创建SpringApplication
实例的时候,会根据用户输入和工程环境做一些基础配置,供之后引导启动中使用。
- 设置
ResourceLoader
和PrimarySources
- 从类中加载
initializer
和listener
放在集合 - 设置是否为Web环境(先确认用户是否指定,未指定则根据工程目录下是否有servlet相关环境)
- 从工程环境中决定主入口的类
run()
——开始引导启动new StopWatch()
——创建计时器StopWatch
是springframework.util
中提供的一个工具类,在启动过程中使用StopWatch
是为了记录启动花费的时间。
Headless模式是在环境缺少显示器等设备情况下的一种配置,和启动流程并无太多关系,不做介绍。configureHeadlessProperty()
——配置Headless模式
监听器可以用来监听SpringApplicationRunListener.start()
——获取监听器,启动监听SpringApplication
启动过程中的各个阶段。默认的监听器是EventPublishRunListener
,用户也可以通过实现SpringApplicationRunListener
接口,实现应用程序对SpringApplication
启动过程的监听。
在 resources/META-INF 下建立 spring.factories 文件,文件中添加 key=value 形式,其中 key 为SpringApplicationRunListener
的全路径名,value 为应用程序对该接口的实现类(类需要一个参数类型为SpringApplication
和 String 数组的构造函数,用于通过反射创建实例)。
在这一步,prepareEnvironment()
——准备环境,创建ConfigurableEnvironment
对象SpringApplication
会创建Spring启动所需的环境,这个环境主要由ConfigurableEnviroment
对象表示。首先,该对象确认了程序是否需要设置Web环境,其次,该对象还确定了程序所需要的参数和读取的配置文件等信息。
此步骤会回调SpringApplicationRunListener
的environmentPrepared()
方法,通知监听器环境已经准备好。
这一步骤其实和启动并没有太大关系,只是会向控制台或是日志中输出Spring的Logo和版本信息。printBanner()
——打印横幅
在准备好环境之后,接下来要做的就是创建应用程序上下文createApplicationContext()
——创建应用程序上下文并加载BeanApplicationContext
对象。ApplicationContext
是Spring IoC的核心组件,它不仅是程序所需Bean的容器,还提供了国际化,事件发布等功能。
在创建应用程序上下文的时候,首先会根据之前配置决定上下文的具体类型(AnnotationConfigApplicationContext
或是AnnotationConfigServletWebServerApplicationContext
)。再通过反射实例化到对象。
虽然已经得到了prepareContext()
——准备ApplicationContext
ApplicationContext
对象,但此时的对象还只是一个空白对象,需要准备和处理后,ApplicationContext
才能被使用。
在准备过程中主要做了做了几件事:为ApplicationContext
设置之前准备好的Environment
对象。
通过对ApplicationContext
后置处理或是BeanDefinitionLoader
等方式往容器中添加一些初始的Bean。
应用默认的初始化器初始化应用程序上下文(责任链模式的应用,多个初始化器形成一个List,应用程序需要被每个初始化器应用一次,每个初始化器有自己的职责)。
准备过程中ApplicationRunListener
发出两个消息,分别是contextPrepared
和contextLoaded
。
在应用程序上下文准备好后,可以通过刷新应用程序上下文发现Bean并加载到容器中。refreshContext()
——刷新上下文refreshContext()
会调用ApplicationContext.refresh()
方法。AbstractApplicationContext
中定义了refresh()
方法的基本框架(模板模式的应用)。
准备刷新的阶段做了初始化和校验的工作。比如初始化启动时间,初始化PropertySources(在prepareRefresh()
——准备刷新AbstractApplicationContext
中只是一个空方法,留给子类根据需要实现),以及校验环境中是否已经有必要的参数。prepareBeanFactory()
——准备BeanFactory
BeanFactory
是 Spring 框架中容器的底层实现,所有的 Bean 都存放在BeanFactory
中,虽然ApplicationContext
也实现了BeanFactory
接口,但是在其内部还是将获取 Bean 的相关操作委托给内部的DefaultListableBeanFactory
变量,只是ApplicationContext
帮用户屏蔽了底层的操作,同时提供出一些更符合外部用户使用的接口。
对BeanFactory的准备主要是:添加一些必要组件,比如类加载器,表达式解析器,属性编辑器注册表等。
以及一些后置处理器,比如ApplicationContextAwareProcessor
(xxxAware
的接口就是通过后置处理器在Bean创建的时候,通过后置处理器设置的)。此外还有一些特殊的Bean,environment
,systemProperties
和systemEnvirnoment
。
对于非postProcessBeanFactory()
——后置处理BeanFactory
WebServlet
环境的ApplicationContext
而言这个方法是个空方法,但是Web环境下的ApplicationContext
会通过这个方法定制一些后处理动作,比如添加WebApplicationContextServletAwareProcessor
后置处理器,添加在web环境中可能使用的Scope(session
和request
)。invokeBeanFactoryPostProcessors()
——实例化并调用BeanFactoryPostProcessor
BeanFactoryPostProcessor
是一种特殊的后置处理器,其操作的对象是针对BeanFactory。
此时主要有三个后置处理器,分别是:SharedMetadataReaderFactoryContextInitializer$CachingMetadataReaderFactoryPostProcessor
,ConfigurationWarningsApplicationContextInitializer$ConfigurationWarningsPostProcessor
和ConfigFileApplicationListener$PropertySourceOrderingPostProcessor
。这三个类名字虽然很长,但是其实是因为内部类的关系,而且看名字也能发现类是怎么来的(外部类是xxxInitializer的就说明是初始化器设置的)。
其中第一个类和启动流程有关,因为它会向容器注册ConfigurationClassPostProcessor
。
如果BeanFactoryPostProcessor
同时又是BeanDefinitionRegistryPostProcessor
,则先进行针对BeanDefinition
注册表的后置处理,目的是为了发现Bean。
在最初的三个BeanFactoryProcessor
后置处理完成后,会从容器中获取BeanDefinitionRegistryPostProcessor
类型的后置处理器(这里主要会得到刚才加载的ConfigurationClassPostProcessor
实例)。再调用这些BeanDefinitionRegistry
的后置处理器,继续向发现并向容器中注册新的Bean。
这里主要是通过@Configuration
注解作为入口发现Bean,如果发现的Bean中又存在新的@Configuration
Bean,则以此Bean为入口再进行发现,直到所有的Bean都被发现。
在针对BeanDefinition
注册表的后置处理完成(发现Bean的过程)中,如果找到了BeanFactoryPostProcessor
(包括最初的三个BeanFatoryProcessor
),会进行针对BeanFactory的后置处理过程(之前只是进行针对注册表的后置处理,二者的目的还是有区别的)。
注意 Bean的发现过程只是向BeanDefinition注册表注册BeanDefinition的过程,并没有针对发现的Bean进行实例化(少部分需要用到的Bean会进行实例化,比如这部分会对BeanDefinitionRegistryPostProcessor
类型的Bean实例化)。
上一步是针对registerBeanPostProcessors()
——注册Bean后置处理器BeanFactory
和BeanDefinitionRegistry
的后置处理器,这一步从BeanFactory中获取针对普通Bean的后置处理器BeanFactoryPostProcessor
放到专门的容器beanPostProcessors
中。initMessageSource()
——初始化MessageSource
MessageSource
是拥有特殊功能的Bean,用来处理国际化相关内容。initApplicationEventMulticaster()
——初始化ApplicationEventMulticaster
ApplicationEventMulticaster
是ApplicationEvent
广播器,可以通过这个对象向容器中添加移除Listener
,也可以通过这个对象发布事件(观察者模式的应用)。
发现了所有的Bean,并且需要实例化的Bean也都被创建好了之后,Spring接下去要做的是创建onRefresh()
——刷新应用程序ThemeSource
(和主题相关的组件),以及创建Webserver(如果是Web环境的话)。
这一步会将初始化得到的registerListeners()
——注册监听器ApplicationListener
方法和容器中获得ApplicationListener
一起注册到ApplicationEventMulticaster
中,并且如果存在需要早起发布的事件,则发布事件。
经过之前的步骤,现在容器中必要的组件都已经准备好了,并且所有需要容器管理的Bean也都已经被发现注册成BeanDefinition注册表中。finishBeanFactoryInitialzation()
——初始化容器中的Bean
对于Scope是Singleton的Bean而言,此时已经具备了实例化Bean的条件,因此在这一步中,Spring会对所有Singleton且非lazy-init的Bean进行实例化。
主要做法就是获取容器中所有为singletion
且非lazyInit
的BeanDefinition
,然后通过getBean创建出Bean的实例,保存在容器内部。
有一种特殊的情况是针对FactoryBean
,FactoryBean
是一种用来创建Bean的特殊Bean,在得到FactoryBean
的Bean之后,还需要判断是否要创建FactoryBean
负责创建的Bean。
Bean的实例化过程getBean()
在以后的文章中再介绍。
在这步主要是一些资源清理以及注册finishRefresh()
——完成刷新LifeCycleProcessor
。LifeCycleProcessor
可以用来在 Spring 生命周期的refresh
和close
时触发回调。并且发布Refresh的消息。
在Application完成刷新后,afterRefresh()
——留给子类的钩子函数SpringApplication
给子类留了afterRefresh()
的方法作为回调。启动完成
启动完成后,stopWatch
会记录下本次启动消费的时间。
然后向ApplicationRunListener
发布started
事件,说明已经启动就绪。准备运行
启动完成后,正式运行前,SpringApplication还会执行用户定义的ApplicationRunner
和CommandLineRunner
两个接口中定义的run()
方法。
在执行完成后,向ApplicationRunListener
发布runing
的消息。至此,启动流程结束。总结
本文旨在对SpringBoot启动流程各个步骤做一次梳理(本文的段落标题就是启动的各个步骤,不同等级的标题也含有方法前后调用的关系),并没有对每行代码做深入分析。如果感兴趣可以对照流程自己分析一遍。另外,在贴一份整理的不错的流程图帮助大家加深印象。