整體流程
SpringBoot啟動(dòng)過程:
上一節(jié)我們討論SpringApplication實(shí)例化的過程塔次,也就是上圖1-9步驟塔嬉,本節(jié)我們討論10關(guān)鍵步驟拍顷,現(xiàn)在主要講是run方法里面的過程
/**
* 啟動(dòng)方法
* @param args
* @return
*/
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
//....省略
try {
//包裝參數(shù)變量
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
//準(zhǔn)備環(huán)境
ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);
//......此處省略代碼
}
準(zhǔn)備環(huán)境
準(zhǔn)備環(huán)境是一個(gè)重要的方法蕊退,主要幫我們配置Java一些環(huán)境茫蛹,把Java環(huán)境屬性加載到內(nèi)存魁蒜,管理起來囊扳,方便我們以后使用吩翻,源碼如下:
/**
* 環(huán)境準(zhǔn)備
* @param listeners 監(jiān)聽管理器
* @param applicationArguments 啟動(dòng)參數(shù)
* @return 返回標(biāo)準(zhǔn)的servlet環(huán)境
*/
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments) {
// 創(chuàng)建一個(gè)新的 ConfigurableEnvironment 實(shí)例或檢索現(xiàn)有實(shí)例。
ConfigurableEnvironment environment = this.getOrCreateEnvironment();
// 根據(jù)命令行參數(shù)配置環(huán)境锥咸。
this.configureEnvironment((ConfigurableEnvironment) environment, applicationArguments.getSourceArgs());
// 將配置屬性源附加到環(huán)境中狭瞎。
ConfigurationPropertySources.attach((Environment) environment);
// 通知監(jiān)聽器環(huán)境已準(zhǔn)備好。
listeners.environmentPrepared((ConfigurableEnvironment) environment);
// 將環(huán)境綁定到 Spring 應(yīng)用程序她君。
this.bindToSpringApplication((ConfigurableEnvironment) environment);
// 檢查是否設(shè)置了自定義環(huán)境脚作。
if (!this.isCustomEnvironment) {
// 如果需要,使用 EnvironmentConverter 轉(zhuǎn)換環(huán)境(例如缔刹,用于類加載)球涛。
environment = (new EnvironmentConverter(this.getClassLoader()))
.convertEnvironmentIfNecessary((ConfigurableEnvironment) environment, this.deduceEnvironmentClass());
}
// 再次附加配置屬性源(如果需要)。
ConfigurationPropertySources.attach((Environment) environment);
// 返回準(zhǔn)備好的環(huán)境校镐。
return (ConfigurableEnvironment) environment;
}
實(shí)例化StandardServletEnvironment對(duì)象
StandardServletEnvironment的父類是StandardEnvironment亿扁,而StandardEnvironment的抽象父類是AbstractEnvironment。類圖如下
在實(shí)例化StandardServletEnvironment的時(shí)候鸟廓,主要是抽象父類添加兩類屬性資源
servletContextInitParams
和servletConfigInitParams
从祝,在StandardEnvironment中又添加了兩類屬性資源systemProperties
和systemEnvironment
。
-
servletContextInitParams
:servlet上下文初始化屬性資源引谜,屬性值目前是一個(gè)obj對(duì)象牍陌。 -
servletConfigInitParams
:servlet配置的屬性資源,屬性值目前也是一個(gè)obj對(duì)象员咽。 -
systemProperties
:Java環(huán)境屬性資源毒涧。 -
systemEnvironment
:操作系統(tǒng)環(huán)境屬性資源。
configureEnvironment配置環(huán)境
改方法主要做三件事贝室,1契讲,是配置環(huán)境的裝換服務(wù)對(duì)象。2滑频,是配置參數(shù)屬性捡偏,就是命令行傳的參數(shù)。3峡迷,配置活躍的環(huán)境银伟,現(xiàn)階段是空。代碼如下
/**
* 配置環(huán)境
* @param environment 環(huán)境對(duì)象
* @param args 命令參數(shù)
*/
protected void configureEnvironment(ConfigurableEnvironment environment, String[] args) {
//這里是true
if (this.addConversionService) {
ConversionService conversionService = ApplicationConversionService.getSharedInstance();
//設(shè)置ConfigurableConversionService對(duì)象
environment.setConversionService((ConfigurableConversionService)conversionService);
}
//配置命令行參數(shù)
this.configurePropertySources(environment, args);
//配置活躍的環(huán)境绘搞,暫時(shí)是空
this.configureProfiles(environment, args);
}
附加配置屬性
ConfigurationPropertySources.attach((Environment) environment);
附加配置屬性資源彤避,之前我們加了四個(gè),現(xiàn)在多個(gè)叫configurationProperties
的屬性資源名看杭。這里附加的屬性資源并無任務(wù)的值。
廣播環(huán)境準(zhǔn)備完成事件
listeners.environmentPrepared((ConfigurableEnvironment) environment);
廣播事件挟伙,下面我們看看支持那些監(jiān)聽器楼雹,并且做了什么事情模孩。符合條件只要7個(gè)監(jiān)聽器,最重要的是ConfigFileApplicationListener
,這個(gè)類就是加載我們配置文件贮缅。
ConfigFileApplicationListener
監(jiān)聽器處理方法榨咐,就是在META-INF下的spring.factories下面的接口EnvironmentPostProcessor
的實(shí)現(xiàn)類,同時(shí)也把ConfigFileApplicationListener
加入到 環(huán)境處理列表中谴供,加載處理實(shí)例一共是五個(gè)块茁,其中兩個(gè)是沒什么用的,源碼如下
//處理事件
private void onApplicationEnvironmentPreparedEvent(ApplicationEnvironmentPreparedEvent event) {
//META-INF/spring.factories下的EnvironmentPostProcessor的所有實(shí)現(xiàn)類
List<EnvironmentPostProcessor> postProcessors = this.loadPostProcessors();
//添加到列表
postProcessors.add(this);
AnnotationAwareOrderComparator.sort(postProcessors);
Iterator<EnvironmentPostProcessor> it = postProcessors.iterator();
while(it.hasNext()) {
EnvironmentPostProcessor postProcessor = it.next();
//處理配置環(huán)境
postProcessor.postProcessEnvironment(event.getEnvironment(), event.getSpringApplication());
}
}
在ConfigFileApplicationListener
中桂肌,有個(gè)Loader
內(nèi)部類数焊,這個(gè)內(nèi)部類初始化會(huì)去META-INF/spring.factories
去找對(duì)應(yīng)的屬性加載器,一共找到兩個(gè)PropertiesPropertySourceLoader
和YamlPropertySourceLoader
崎场,分別處理yml
文件和properties
后綴的文件佩耳。
Loader(ConfigurableEnvironment environment, ResourceLoader resourceLoader) {
this.logger = ConfigFileApplicationListener.this.logger;
this.loadDocumentsCache = new HashMap<>();
this.environment = environment;
//解析參數(shù)
this.placeholdersResolver = new PropertySourcesPlaceholdersResolver(this.environment);
this.resourceLoader = (ResourceLoader)(resourceLoader != null ? resourceLoader : new DefaultResourceLoader((ClassLoader)null));
//屬性文件加載列表
this.propertySourceLoaders = SpringFactoriesLoader.loadFactories(PropertySourceLoader.class, this.getClass().getClassLoader());
}
程序執(zhí)行到這里,所有的配置屬性都加載到環(huán)境中谭跨,包括外部配置和內(nèi)部配置干厚。