SpringBoot源码启动流程(待完善)
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
创建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);}
配置解析流程
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).