目录
SpringApplicationRunListener.starting
SpringApplicationRunListeners.environmentPrepared
ApplicationContextInitializer初始化
SpringApplicationRunListener.contextPrepared
SpringApplicationRunListener.contextLoaded
SpringApplicationRunListener.started
SpringApplicationRunListener.running
SpringBoot源码启动流程
1. 构造SpringApplication对象
1.1 推测web应用类型
判断关键类是否存在来区分类型
- REACTIVE
- NONE
- SERVLET
static WebApplicationType deduceFromClasspath() {
if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null) && !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null)
&& !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) {
return WebApplicationType.REACTIVE;
}
for (String className : SERVLET_INDICATOR_CLASSES) {
if (!ClassUtils.isPresent(className, null)) {
return WebApplicationType.NONE;
}
}
return WebApplicationType.SERVLET;
}
2. 设置Initializers和Listeners扩展点
3. 推测Main方法所在类
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
// 推测web应用
this.webApplicationType = WebApplicationType.deduceFromClasspath();
// 设置Initializer和Listener扩展点
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
// 推测main方法所在类
this.mainApplicationClass = deduceMainApplicationClass();
}
2. run(String... args)方法
SpringApplicationRunListener.starting
SpringBoot提供了一个EventPublishingRunListener,它实现了SpringApplicationRunListener接口,默认情况下会利用EventPublishingRunListener发布一个ApplicationContextInitializedEvent事件,程序员可通过定义ApplicationListener来消费这个事件
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();
创建Environment
解析配置文件, 环境变量, 启动命令参数
SpringApplicationRunListeners.environmentPrepared
用EventPublishingRunListener发布一个ApplicationEnvironmentPreparedEvent事件,默认情况会有一个EnvironmentPostProcessorApplicationListener来消费这个事件,而这个ApplicationListener接收到这个事件之后,就会解析application.properties、application.yml文件,并添加到Environment对象中去。
打印Banner
控制台打印启动springboot日志
创建Spring容器
protected ConfigurableApplicationContext createApplicationContext() {
Class<?> contextClass = this.applicationContextClass;
if (contextClass == null) {
try {
switch (this.webApplicationType) {
case SERVLET:
contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);
break;
case REACTIVE:
contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);
break;
default:
contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);
}
}
catch (ClassNotFoundException ex) {
throw new IllegalStateException(
"Unable create a default ApplicationContext, " + "please specify an ApplicationContextClass",
ex);
}
}
return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
}
ApplicationContextInitializer初始化
默认SpringBoot提供了多个ApplicationContextInitializer,其中比较重要的有ConditionEvaluationReportLoggingListener
ConditionEvaluationReportLoggingListener.initialize逻辑:
public void initialize(ConfigurableApplicationContext applicationContext) {
// 设置spring容器
this.applicationContext = applicationContext;
// 添加监听器
applicationContext.addApplicationListener(new ConditionEvaluationReportListener());
// 生成一个ConditionEvaluationReport对象赋值给report属性
if (applicationContext instanceof GenericApplicationContext) {
this.report = ConditionEvaluationReport.get(this.applicationContext.getBeanFactory());
}
}
ConditionEvaluationReportListener会负责接收ContextRefreshedEvent事件,也就是Spring容器一旦启动完毕就会触发ContextRefreshedEvent,ConditionEvaluationReportListener就会打印自动配置类的条件评估报告。
SpringApplicationRunListener.contextPrepared
发布一个ApplicationContextInitializedEvent广播事件, 默认没有Listener消费
将启动类作为配置类注册到spring容器
private int load(Class<?> source) {
if (isGroovyPresent() && GroovyBeanDefinitionSource.class.isAssignableFrom(source)) {
// Any GroovyLoaders added in beans{} DSL can contribute beans here
GroovyBeanDefinitionSource loader = BeanUtils.instantiateClass(source, GroovyBeanDefinitionSource.class);
load(loader);
}
// 注册配置类
if (isComponent(source)) {
this.annotatedReader.register(source);
return 1;
}
return 0;
}
SpringApplicationRunListener.contextLoaded
默认情况下会利用EventPublishingRunListener发布ApplicationPreparedEvent事件
刷新spring容器
refreshContext会调用spring的refresh方法
SpringApplicationRunListener.started
发布ApplicationStartedEvent事件
callRunners
调用ApplicationRunner和CommandLineRunner的run方法
SpringApplicationRunListener.running
发布ApplicationReadyEvent事件
handleRunFailure处理异常
发布ApplicationFailedEvent事件
配置解析流程
- 添加servlet, servlet容器, 操作系统, JVM环境变量的配置
- 添加默认配置defaultProperties
- 添加命令行参数addCommandLineProperties
- 添加RandomValuePropertySource(ConfigFileApplicationListener消费ApplicationEnvironmentPreparedEvent事件)
- 添加参数-Dspring.application.json参数的配置项(ConfigFileApplicationListener消费ApplicationEnvironmentPreparedEvent事件)
SpringBoot配置优先级
官网描述:Core Features
-
Default properties (specified by setting
SpringApplication.setDefaultProperties
). -
@PropertySource annotations on your
@Configuration
classes. Please note that such property sources are not added to theEnvironment
until the application context is being refreshed. This is too late to configure certain properties such aslogging.*
andspring.main.*
which are read before refresh begins. -
Config data (such as
application.properties
files). -
A
RandomValuePropertySource
that has properties only inrandom.*
. -
OS environment variables.
-
Java System properties (
System.getProperties()
). -
JNDI attributes from
java:comp/env
. -
ServletContext
init parameters. -
ServletConfig
init parameters. -
Properties from
SPRING_APPLICATION_JSON
(inline JSON embedded in an environment variable or system property). -
Command line arguments.
-
properties
attribute on your tests. Available on @SpringBootTest and the test annotations for testing a particular slice of your application. -
@DynamicPropertySource annotations in your tests.
-
@TestPropertySource annotations on your tests.
-
Devtools global settings properties in the
$HOME/.config/spring-boot
directory when devtools is active.
Config data files are considered in the following order:
-
Application properties packaged inside your jar (
application.properties
and YAML variants). -
Profile-specific application properties packaged inside your jar (
application-{profile}.properties
and YAML variants). -
Application properties outside of your packaged jar (
application.properties
and YAML variants). -
Profile-specific application properties outside of your packaged jar (
application-{profile}.properties
and YAML variants).