Spring Boot启动
Spring Boot项目若从main方法启动,走的是SpringApplication的run方法来启动spring容器,从main的入口开始,一步一步往下看:
1 |
|
接下来就是SpringApplication的run方法了,进入了Spring的流程:
1 | public static ConfigurableApplicationContext run(Object source, String... args) { |
到这一步可以看到,整个启动流程分为两个步骤:初始化一个SpringApplication对象、执行该对象的run方法。
SpringApplication对象初始化
首先看SpringApplication创建的时候是怎么初始化的:
1 | public SpringApplication(Object... sources) { |
这里的信息量还是不少的:
getSpringFactoriesInstances
getSpringFactoriesInstances方法,其作用是找到spring.factories中配置的接口的实现类,这里是用来获取ApplicationContextInitializer和ApplicationListener的实现类
实现方式是利用SpringFactoriesLoader查找META-INF/spring.factories下的配置,按properties取值:
1 | private <T> Collection<? extends T> getSpringFactoriesInstances(Class<T> type, |
ApplicationContextInitializer
ApplicationContextInitializer的作用, 是在应用的上下文ConfigurableApplicationContext做refresh之前,对ConfigurableApplicationContext实例做进一步的设置或处理。而ConfigurableApplicationContext接口继承了ApplicationContext接口。
ApplicationListener
ApplicationListener就是spring中定义的监听器,用来监听后面SpringApplicationRunListener发布的消息,可以在应用启动中监听应用的不同阶段,做不同的操作。
SpringApplication启动
看完了初始化,看一下SpringApplication是怎么run起来的吧:
1 | public ConfigurableApplicationContext run(String... args) { |
说一说几个关键的阶段
SpringApplicationRunListener
同样是利用SpringFactoriesLoader从spring.factories中查找SpringApplicationRunListener的实现类,只有一个EventPublishingRunListener,本质是一个事件发布者。
事件发布
在应用的不同阶段,发布不同的事件,通知感兴趣的监听器在初始化的过程中做不同的操作。
发布事件的阶段分别在应用开始启动、Environment创建好后、ApplicationContext创建好后、ApplicationContext加载完成且refresh调用前、run方法结束调用前,
事件监听
SpringApplication初始化时加载的ApplicationListener监听各个阶段相关的事件
Environment
Environment主要抽象了配置文件(profile)和属性(properties),当Environment准备好后,在整个应用的任何时候,都可以从Environment中获取资源
ApplicationContext
初始化ApplicationContext
初始化ApplicationContext时的主要工作:
- 设置准备好的Environment
- 执行所有ApplicationContextInitializer的initialize方法
- 发布contextPrepared事件通知监听者
- 将所有的bean加载到容器中
- 发布contextLoaded事件通知监听者
刷新ApplicationContext
refreshContext方法一路点进去,就会发现最终调的还是AbstractApplicationContext的refresh方法:
1 | public void refresh() throws BeansException, IllegalStateException { |
相信看过spring源码的,对spring初始化了解的都对这段代码很熟…