1、SpringBoot启动过程源码解析
2、SpringBoot启动过程中扩展点源码解析
3、SpringBoot配置文件优先级解析
4、SpringBoot内置Tomcat启动源码解析
SpringBoot 启动类:
@SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
// 先构造SpringApplication对象,再执行run方法
return new SpringApplication(primarySources).run(args);
}
org.springframework.boot.SpringApplication#SpringApplication(org.springframework.core.io.ResourceLoader, java.lang.Class>…)
org.springframework.boot.WebApplicationType#deduceFromClasspath
说明:
org.springframework.web.reactive.DispatcherHandler
,并且不存在org.springframework.web.servlet.DispatcherServlet
,那么应用类型为WebApplicationType.REACTIVE
org.springframework.web.reactive.DispatcherHandler
,也不存在org.springframework.web.servlet.DispatcherServlet
,那么应用类型为WebApplicationType.NONE
WebApplicationType.SERVLET
没什么具体的作用,逻辑是根据当前线程的调用栈来判断main()方法在哪个类,哪个类就是Main类。
默认情况下SpringBoot提供了一个EventPublishingRunListener,它实现了SpringApplicationRunListener接口,默认情况下会利用EventPublishingRunListener发布一个ApplicationContextInitializedEvent事件,程序员可以通过定义ApplicationListener来消费这个事件
Environment对象表示环境变量,该对象内部主要包含了:
默认情况下会利用EventPublishingRunListener发布一个ApplicationEnvironmentPreparedEvent事件,程序员可以通过定义ApplicationListener来消费这个事件,比如默认情况下会有一个EnvironmentPostProcessorApplicationListener来消费这个事件,而这个ApplicationListener接收到这个事件之后,就会解析application.properties、application.yml
文件,并添加到Environment对象中去。
没什么特殊的。
会利用ApplicationContextFactory.DEFAULT
,根据应用类型创建对应的Spring容器。ApplicationContextFactory.DEFAULT
为:
ApplicationContextFactory DEFAULT = (webApplicationType) -> {
try {
switch (webApplicationType) {
case SERVLET:
return new AnnotationConfigServletWebServerApplicationContext();
case REACTIVE:
return new AnnotationConfigReactiveWebServerApplicationContext();
default:
return new AnnotationConfigApplicationContext();
}
}
catch (Exception ex) {
throw new IllegalStateException("Unable create a default ApplicationContext instance, "
+ "you may need a custom ApplicationContextFactory", ex);
}
};
所以:
默认情况下SpringBoot提供了多个ApplicationContextInitializer,其中比较重要的有ConditionEvaluationReportLoggingListener,别看到它的名字叫XXXListener,但是它确实是实现了ApplicationContextInitializer接口的。
在它的initialize()方法中会:
ConditionEvaluationReportListener会负责接收ContextRefreshedEvent事件,也就是Spring容器一旦启动完毕就会触发ContextRefreshedEvent,ConditionEvaluationReportListener就会打印自动配置类的条件评估报告。
默认情况下会利用EventPublishingRunListener发布一个ApplicationContextInitializedEvent事件,默认情况下暂时没有ApplicationListener消费了这个事件
没什么特殊的,忽略。
将SpringApplication.run(MyApplication.class);
中传入进来的类,比如MyApplication.class
,作为Spring容器的配置类。
默认情况下会利用EventPublishingRunListener发布一个ApplicationPreparedEvent事件。
调用Spring容器的refresh()方法,结合第9、13步,相当于执行了这样一个流程:
发布ApplicationStartedEvent事件和AvailabilityChangeEvent事件,AvailabilityChangeEvent事件表示状态变更状态,变更后的状态为LivenessState.CORRECT
LivenessState枚举有两个值:
发布ApplicationReadyEvent事件和AvailabilityChangeEvent事件,AvailabilityChangeEvent事件表示状态变更状态,变更后的状态为ReadinessState.ACCEPTING_TRAFFIC
ReadinessState枚举有两个值:
发布ApplicationFailedEvent事件。
与自定义配置中心相关,比如 nacos,将配置信息载入到 Environment 对象中。
添加 servlet、servlet 容器、操作系统、JVM 环境变量,比如:
# JVM环境变量
java -jar -Dserver.port=8888 springbootdemo.jar
# 命令行变量
java -jar springbootdemo.jar --server.port=8888
优先级高到低:
添加默认的,通过SpringApplication的setDefaultProperties()方法设置的。
优先级高到低:
把命令行中的参数封装成PropertySource,添加到Environment对象中。
添加运行时命令行中设置的参数,比如:
java -jar springbootdemo.jar --server.port=8888
优先级高到低:
添加一个能产生随机数的,没啥用。
优先级高到低:
从已有Environment中读取spring.application.json
配置,添加-Dspring.application.json
参数配置的。
优先级高到低:
如果当前是在CLOUD_FOUNDRY上,则添加平台相关的。
优先级高到低:
获取如下三个参数指定的路径:
spring.config.location(如果指定了,默认的会失效)
spring.config.import(在默认的基础上新增)
spring.config.additional-location(在默认的基础上新增)
查找配置文件目录,顺序如下:classpath:/firechou/
,通过配置新增的;optional:file:./config/*/
;optional:file:./config/
;optional:file:./
;optional:classpath:/config/
;optional:classpath:/
;
optional 表示可选的,文件没有不会报错;
file 表示打包后的 jar 文件所在目录;
classpath 表示 target 所在目录;
去各个目录下找配置文件,可以通过spring.config.name
来配置文件名,默认为application。
如下:classpath:/firechou/application.yaml、application.yml、application.xml、application.properties
;file:./application.yaml、application.yml、application.xml、application.properties
;file:./config/application.yaml、application.yml、application.xml、application.properties
;file:./config/*/application.yaml、application.yml、application.xml、application.properties
;classpath:/application.yaml、application.yml、application.xml、application.properties
;classpath:/config/application.yaml、application.yml、application.xml、application.properties
;
说明:
倒序,所以properties的优先级高于yml,实际看具体的 springboot 版本;
用户指定的配置文件路径优先级最高,默认情况下file目录高于classpath目录;
解析上述所有路径,解析真正存在的文件路径。
注意,这里并不是解析每个文件生成PropertySource,添加到Environment对象中,这里只是先解析出来PropertySource对象,并按顺序放到一个集合里面。
从以上所有配置中找spring.profiles.active
,找出对应的值,然后按指定的值再去找对应的文件,比如dev。
在每个配置文件中可以通过以下方式来指定配置文件生效的前提:spring.config.activate.on-profile=dev
;spring.config.activate.on-cloudPlatform=CLOUD_FOUNDRY
;
按当前的支持的profiles和cloudPlatform来过滤,配置文件中没有配的,以及匹配的则会胜出;
把最后胜出的配置文件生成对应的PropertySource添加到Environment中;
优先级高到低:
参考官网:https://docs.spring.io/spring-boot/docs/current/reference/html/features.html#features.external-config
优先级由低到高:
1.Default properties (specified by setting SpringApplication.setDefaultProperties). // 默认配置
2.@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.
3.Config data (such as application.properties files). // classpath或jar同级目录下的配置
4.A RandomValuePropertySource that has properties only in random.*.
5.OS environment variables. // 操作系统环境变量参数
6.Java System properties (System.getProperties()). // JVM参数
7.JNDI attributes from java:comp/env. // 不管它
8.ServletContext init parameters.
9.ServletConfig init parameters.
10.Properties from SPRING_APPLICATION_JSON (inline JSON embedded in an environment variable or system property).
11.Command line arguments. // 命令行
12.properties attribute on your tests. Available on @SpringBootTest and the test annotations for testing a particular slice of your application.
13.@TestPropertySource annotations on your tests.
14.Devtools global settings properties in the $HOME/.config/spring-boot directory when devtools is active.
说明: