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对象中去。
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);
}
官网描述: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).