目录
SpringBoot源码启动流程
1. 构造SpringApplication对象
2. run(String... args)方法
SpringApplicationRunListener.starting
创建Environment
SpringApplicationRunListeners.environmentPrepared
打印Banner
创建Spring容器
ApplicationContextInitializer初始化
SpringApplicationRunListener.contextPrepared
将启动类作为配置类注册到spring容器
SpringApplicationRunListener.contextLoaded
刷新spring容器
SpringApplicationRunListener.started
callRunners
SpringApplicationRunListener.running
handleRunFailure处理异常
配置解析流程
SpringBoot配置优先级
1.1 推测web应用类型
判断关键类是否存在来区分类型
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();
}
SpringBoot提供了一个EventPublishingRunListener,它实现了SpringApplicationRunListener接口,默认情况下会利用EventPublishingRunListener发布一个ApplicationContextInitializedEvent事件,程序员可通过定义ApplicationListener来消费这个事件
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();
解析配置文件, 环境变量, 启动命令参数
用EventPublishingRunListener发布一个ApplicationEnvironmentPreparedEvent事件,默认情况会有一个EnvironmentPostProcessorApplicationListener来消费这个事件,而这个ApplicationListener接收到这个事件之后,就会解析application.properties、application.yml文件,并添加到Environment对象中去。
控制台打印启动springboot日志
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);
}
默认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就会打印自动配置类的条件评估报告。
发布一个ApplicationContextInitializedEvent广播事件, 默认没有Listener消费
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;
}
默认情况下会利用EventPublishingRunListener发布ApplicationPreparedEvent事件
refreshContext会调用spring的refresh方法
发布ApplicationStartedEvent事件
调用ApplicationRunner和CommandLineRunner的run方法
发布ApplicationReadyEvent事件
发布ApplicationFailedEvent事件
官网描述: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 the Environment
until the application context is being refreshed. This is too late to configure certain properties such as logging.*
and spring.main.*
which are read before refresh begins.
Config data (such as application.properties
files).
A RandomValuePropertySource
that has properties only in random.*
.
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).