springboot的源碼(spring)主要分為幾個部分
1惠勒、構(gòu)造SpringApplication,完成spring.factories文件中Initializers與Listeners的加載
2、加載配置文件爱致,通過ConfigFileApplicationListener
3、加載BeanDefinitionRegistryPostProcessor與BeanFactoryPostProcessor完成bean的定義包裝(非生成實例)
4、生成bean實例以及初始化
本文主要針對第二點嘱么,主要看如何加載配置文件,即如何加載環(huán)境信息顽悼,主要通過ConfigFileApplicationListener完成基于springboot2.1.4
項目地址:https://gitee.com/eshin/springbootdemo.git#autotest
org.springframework.boot.SpringApplication#run(java.lang.String...)-->org.springframework.boot.SpringApplication#prepareEnvironment
該方法主要看兩部分
有圖可以看出几迄,在構(gòu)造StandardServletEnvironment的時候,父類的構(gòu)造器依次執(zhí)行冰评,構(gòu)造后的StandardServletEnvironment就包含了如下的propertySource映胁,主要是系統(tǒng)參數(shù)
1曼振、系統(tǒng)環(huán)境信息配置初始化加載org.springframework.boot.SpringApplication#getOrCreateEnvironment
2、發(fā)布environmentPrepared事件甲雅,ConfigFileApplicationListener監(jiān)聽到后執(zhí)行
environmentPrepared事件的發(fā)布解孙,此處不做詳述,可參考此處,其中監(jiān)聽到事件的Listener就有ConfigFileApplicationListener抛人,其實現(xiàn)了EnvironmentPostProcessor接口和SmartApplicationListener接口弛姜。
因此在org.springframework.boot.context.config.ConfigFileApplicationListener#onApplicationEnvironmentPreparedEvent遍歷執(zhí)行EnvironmentPostProcessor的時候,就會執(zhí)行到org.springframework.boot.context.config.ConfigFileApplicationListener#postProcessEnvironment妖枚,然后通過org.springframework.boot.context.config.ConfigFileApplicationListener#addPropertySources執(zhí)行到org.springframework.boot.context.config.ConfigFileApplicationListener.Loader#load()
在上圖中廷臼,this.propertySourceLoaders在spring.factories中配置,可自定義loader并配置绝页。
- initializeProfiles();中會根據(jù)系統(tǒng)參數(shù)設(shè)置activeProfiles,如果有設(shè)置的話荠商,沒有就只有default一個⌒可以在運行springboot項目的時候設(shè)置spring.profiles.active莱没,或者spring.profiles.include。本文的前提是沒有在系統(tǒng)參數(shù)中設(shè)置這兩個變量屈芜,流程差不多郊愧,就是在this.profiles.poll()多走幾個循環(huán)而已。
- 進入org.springframework.boot.context.config.ConfigFileApplicationListener.Loader#load(Profile profile, DocumentFilterFactory filterFactory,DocumentConsumer consumer)
進入org.springframework.boot.context.config.ConfigFileApplicationListener.Loader#loadForFileExtension->org.springframework.boot.context.config.ConfigFileApplicationListener.Loader#load(PropertySourceLoader loader, String location, Profile profile,DocumentFilter filter, DocumentConsumer consumer)
圖中中間位置
其中List<Document> documents = loadDocuments(loader, name, resource);
然后回到load方法中
最終通過loaded.forEach((document) -> consumer.accept(profile, document));將加載到的配置放入environment的properSourceList中
其中MutablePropertySources::addLast的方法引用方式比較少見井佑,可參考此處
至此属铁,整個environment的配置加載過程就完成了。
3躬翁、配置項的注入
配置項的注入是要等到bean的實例化后初始化階段焦蘑,參考這里.實例化后,會通過org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor#postProcessProperties-->org.springframework.beans.factory.annotation.InjectionMetadata#inject--->org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.AutowiredMethodElement#inject--->org.springframework.beans.factory.support.DefaultListableBeanFactory#resolveDependency--->org.springframework.beans.factory.support.DefaultListableBeanFactory#doResolveDependency
--->org.springframework.beans.factory.support.AbstractBeanFactory#resolveEmbeddedValue然后進入org.springframework.context.support.PropertySourcesPlaceholderConfigurer#processProperties(org.springframework.beans.factory.config.ConfigurableListableBeanFactory, org.springframework.core.env.ConfigurablePropertyResolver)中已經(jīng)定義的StringValueResolver
PropertySourcesPlaceholderConfigurer實現(xiàn)了BeanFactoryPostProcessor的postProcessBeanFactory接口方法盒发,在bean的定義階段就已經(jīng)執(zhí)行其實現(xiàn)的接口方法例嘱,將StringValueResolver添加到beanFactory的embeddedValueResolvers中
總結(jié):
- 1、當系統(tǒng)啟動參數(shù)中配置指定的目錄spring.config.location宁舰,和文件名spring.config.name拼卵,則直接從讀取改配置文件,否則使用默認路徑蛮艰,查找順序為file:./config/腋腮,file:./,classpath:/config/,classpath:/即寡,默認文件名為application徊哑。
- 2、只要加載的配置文件中包含spring.profiles.active,且對應(yīng)的文件沒有加載過聪富,那下次循環(huán)中就會繼續(xù)加載對應(yīng)的配置文件莺丑。
- 3、每個實現(xiàn)org.springframework.boot.env.PropertySourceLoader的loader墩蔓,都需要指定對應(yīng)支持的拓展名梢莽。
- 4、若有多個loader對相同拓展名的配置文件處理钢拧,優(yōu)先級高的loader加載蟹漓,后續(xù)的loader處理時略過。
- 5源内、讀取配置時從propertySourceList中按順序查找,先放入list中的source中讀到了配置份殿,就不往后面查找膜钓,因此配置的生效順序為:系統(tǒng)參數(shù)->file:./config/ -> file:./ -> classpath:/config/ -> classpath:/
指定了profile的要比沒有指定的優(yōu)先。