1 SpringBoot启动的流程总览
每一个SpringBoot程序都有一个主入口,这个主入口就是main方法,而main方法中都会调用SpringBootApplication.run
方法,一个快速了解SpringBootApplication
启动过程的好方法就是在run方法中打一个断点,然后通过Debug的模式启动工程,逐步跟踪了解SpringBoot源码是如何完成环境准备和启动加载bean的。
查看SpringBootApplication.run
方法的源码就可以发现SpringBoot
启动的流程主要分为两大阶段:
- 初始化
SpringApplication
运行SpringApplication
- 运行
SpringApplication
的过程
其中运行SpringApplication
的过程又可以细分为以下几个部分:
1)SpringApplicationRunListeners
引用启动监控模块
2)ConfigrableEnvironment
配置环境模块和监听:包括创建配置环境、加载属性配置文件和配置监听
3)ConfigrableApplicationContext
配置应用上下文:包括配置应用上下文对象、配置基本属性和刷新应用上下文
2 初始化SpringApplication
步骤1进行SpringApplication
的初始化,配置基本的环境变量、资源、构造器、监听器,初始化阶段的主要作用是为运行SpringApplication
实例对象启动环境变量准备以及进行必要的资源构造器的初始化动作,代码如下:
public SpringApplication(ResourceLoader resourceLoader, Object... sources){
this.resourceLoader = resourceLoader;
initialize(source);
}
@SupressWarnings({"unchecked","rowtypes"})
private void initialize(Object[] sources){
if(sources != null && sources.length > 0){
this.sources.addAll(Arrays.asList(sources));
}
this.WebEnvironment = deduceWebEnvironment;
setInitiallizers((Collection) getSpringFactoriesInstances(ApplicationContextInitiallizer.class));
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = deduceMainApplicationClass();
}
SpringApplication
方法的核心就是this.initialize(sources)
初始化方法,SpringApplication
通过调用该方法完成初始化工作。deduceWebEnvironment
方法用来判断当前应用的环境,该方法通过获取两个类来判断当前环境是否是Web环境。而getSpringFactoriesInstances
方法主要用来从spring.factories
文件中找出Key为ApplicationContextInitiallizer
的类并实例化,然后调用setInitiallizer
方法设置到SpringApplication
的initiallizer
属性中,找到它所有应用的初始化器。接着调用setListener方法设置应用监听器,这个过程可以找到所有应用程序的监听器,然后找到应用启动主类名称。
3 运行SpringApplication
SpringBoot
正式启动加载过程,包括启动流程监控模块、配置环境加载模块、ApplicationContext
容器上下文环境加载模块。refreshContext
方法刷新应用上下文并进行自动化配置模块加载,也就是上文提到的SpringFactoriesLoader
根据指定classpath
加载META-INF/spring.factories
文件的配置,实现自动配置核心功能。运行SpringApplication
的主要代码如下:
public ConfigurableApplicationContext run(String... args) {
ConfigurableApplicationContext context = null;
FailureAnalyzer analyzer = null;
configureHeadlessProperty();
// 步骤1
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();
try{
// 步骤2
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
Banner printBanner = printBanner(environment);
// 步骤3
context = createApplicationContext();
prepareContext(context, environment, listeners, applicationArguments, printBanner);
refreshContext(context);
afterRefresh(context, applicationArguments);
listeners.finished(context, null);
// 省略
return context;
}
}
3.1 SpringApplciationRunListener应用启动监控模块
应用启动监控模块对应上述源码中的注释步骤1到步骤2之间的两行代码,它创建了应用的监听器SpringApplicationRunListeners
并开始监听,监控模块通过调用getSpringFactoriesInstances
私有协议从META-INF/spring.factories
文件中取得SpringApplicationRunListener
监听器实例。
当前事件监听器SpringApplicationRunListener
中只有一个EventPublishingRunlistener
广播事件监听器,它的starting
方法会封装成SpringApplicatiionEvent
事件广播出去,被SpringApplication
中配置的listener
监听。这一步骤执行完成后也会同时通知SpringBoot
其他模块目前监听初始化已经完成,可以开始执行启动方案了。
3.2 ConfigurableEnviroment 配置环境模块和监听
对应上述源码注释中的步骤2到步骤3之间的几行代码,下面分解步骤说明:
(1) 创建配置环境,创建应用程序的环境信息。如果是Web程序,创建StandardServletEnvironment
;否则创建StandardEnviroment;
(2) 加载属性配置文件,将配置文件加入监听器对象中(SpringApplicationRunListeners)。通过configPropertySource
方法设置properties
配置文件,通过执行configProfies
方法设置profiles
;
(3) 配置监听,发布environmentPrepared
事件,及调用ApplicationListener#onApplicationEvent
方法,通知SpringBoot
应用的environment
已经准备完成。
3.3 ConfigurableApplicationContext配置应用上下文
对应源码中的步骤3下面的几行代码,下面分解步骤说明:
(1)配置Spring容器应用上下文对象,它的作用是创建Run方法的返回对象ConfigurableApplicationContext
(应用配置上下文),此类主要继承了ApplicationLifeCycle
、Closeable
接口,而ApplicationContext
是Spring框架中负责Bean注入容器的主要载体,负责bean加载、配置管理、维护bean之间依赖关系及Bean生命周期管理。
(2)配置基本属性,对应prepareContext
方法将listener、environment、banner、applicationArguments
等重要组件与Spring容器上下文对象关联。借助SpringFactoriesLoader
查找可用的ApplciationContextInitailizer
, 它的initialize方法会对创建好的ApplicationContext
进行初始化,然后它会调用SpringApplicationRunListener#contextPrepared
方法,此时SpringBoot应用的ApplicationContext
已经准备就绪,为刷新应用上下文准备好了容器。
(3)刷新应用上下文,对应源码中的refreshContext(context)
方法将通过工程模式产生应用上下文中所需的bean。实现spring-boot-starter-*(mybatis、redis等)自动化配置的关键,包括spring.factories的加载、bean的实例化等核心工作。然后调用SpringApplicationRunListener#finish
方法告诉SprignBoot应用程序,容器已经完成ApplicationContext装载。
4 小结
SpringBoot
应用程序的启动流程主要包括初始化SpringApplication
和运行SpringApplication
两个过程。其中初始化SpringApplication
包括配置基本的环境变量、资源、构造器和监听器,为运行SpringApplciation
实例对象作准备;而运行SpringApplication
实例为应用程序正式启动加载过程,包括SpringApplicationRunListeners
引用启动监控模块、ConfigrableEnvironment
配置环境模块和监听及ConfigrableApplicationContext
配置应用上下文。当完成刷新应用的上下文和调用SpringApplicationRunListener#contextPrepared
方法后表示SpringBoot
应用程序已经启动完成。