springboot加載application配置文件源碼分析


springboot加載application.yml和application.properties原理

監聽器:ConfigFileApplicationListener、BootstrapApplicationListener

 

1、系統啟動時,調用SpringApplication.run()

2、初始化監聽器

//初始化SpringApplicationRunListeners,並且初始化變量listeners,將EventPublishingRunListener存放與listeners中

1)SpringApplicationRunListeners listeners = this.getRunListeners(args);

2)

 

3)SpringFactoriesLoader.loadSpringFactories()加載META-INF/spring.factories下的配置監聽器

3、調用ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);內部調用步驟如下

1)listeners.environmentPrepared((ConfigurableEnvironment)environment);

​ 監聽器的准備工作

2)listener.environmentPrepared(environment);

​ 循環listeners中的監聽器,執行environmentPrepared方法,其中加載配置文件的監聽器就在循環列表中

3)執行EventPublishingRunListener中的environmentPrepared()方法

public void environmentPrepared(ConfigurableEnvironment environment) {
       this.initialMulticaster.multicastEvent(new ApplicationEnvironmentPreparedEvent(this.application, this.args, environment));
  }

4)SimpleApplicationEventMulticaster類中的doInvokeListener()方法

5)執行ConfigFiledApplicationListerner類中的onApplicationEvent(event)方法

6)執行ConfigFileApplicationListener中的onApplicationEnviromentPrepareEvent()方法

private void onApplicationEnvironmentPreparedEvent(ApplicationEnvironmentPreparedEvent event) {
       List<EnvironmentPostProcessor> postProcessors = this.loadPostProcessors();
       postProcessors.add(this);
       AnnotationAwareOrderComparator.sort(postProcessors);
       Iterator var3 = postProcessors.iterator();

       while(var3.hasNext()) {
           EnvironmentPostProcessor postProcessor = (EnvironmentPostProcessor)var3.next();
           postProcessor.postProcessEnvironment(event.getEnvironment(), event.getSpringApplication());
      }

  }

注意:AnnotationAwareOrderComparator.sort(postProcessors); 對List<EnvironmentPostProcessor>集合進行排序,排序規則按照spring中的注解@Order注解和@Priority注解排序

7)迭代postPrccessors集合,並且執行集合中的postProcessEnvironment方法,重點看ConfigFileApplicationListener類中的postProcessEnvironment方法

其中會添加一個屬性源進來ResourceLoader

8)調用load方法加載屬性


protected void addPropertySources(ConfigurableEnvironment environment, ResourceLoader resourceLoader) {
       RandomValuePropertySource.addToEnvironment(environment);
      (new ConfigFileApplicationListener.Loader(environment, resourceLoader)).load();
  }

9) load方法中調用apply方法


void load() {
FilteredPropertySource.apply(this.environment, DEFAULT_PROPERTIES, LOAD_FILTERED_PROPERTY,
(defaultProperties) -> {
this.profiles = new LinkedList<>();
this.processedProfiles = new LinkedList<>();
this.activatedProfiles = false;
this.loaded = new LinkedHashMap<>();
initializeProfiles();
while (!this.profiles.isEmpty()) {
Profile profile = this.profiles.poll();
if (isDefaultProfile(profile)) {
addProfileToEnvironment(profile.getName());
}
load(profile, this::getPositiveProfileFilter,
addToLoaded(MutablePropertySources::addLast, false));
this.processedProfiles.add(profile);
}
load(null, this::getNegativeProfileFilter, addToLoaded(MutablePropertySources::addFirst, true));
addLoadedPropertySources();
applyActiveProfiles(defaultProperties);
});
}

10) apply方法默認獲取defaultProperties屬性,如果獲取為空,則從上一步中執行函數式編程中的accept方法,下邊移步到accept方法一探究竟,首先apply方法中會執行一個初始化方法initializeProfiles,方法中會向profiles中放入null,然后再放入一個"default",用來從外部遍歷,遍歷為null的時候,加載springboot的默認配置,遍歷為“default"時,加載用戶配置,從而充分體現了約定大於配置

 

11)遍歷profiles集合,遍歷的第一次為null,執行load方法如下


private void load(Profile profile, DocumentFilterFactory filterFactory, DocumentConsumer consumer) {
getSearchLocations().forEach((location) -> {
boolean isDirectory = location.endsWith("/");
Set<String> names = isDirectory ? getSearchNames() : NO_SEARCH_NAMES;
names.forEach((name) -> load(location, name, profile, filterFactory, consumer));
});
}

 

首先執行getSearchLocations方法,獲取默認的路徑,默認的路徑為如果啟動參數中有"spring.config.location",則加載spring.config.location中指定的配置文件,否則用默認的DEFAULT_SEARCH_LOCATIONS,

classpath:/,classpath:/config/,file:./,file:./config/*/,file:./config/

12)取出Locations為classpath:/,classpath:/config/,file:./,file:./config/*/,file:./config/

遍歷set,按照先后順序取配置文件

13)獲取配置文件名字,如果配置spring.confing.name的話,則去配置的名字,否則用默認的"application"

14)取到location和name之后,執行load(String location, String name, Profile profile, DocumentFilterFactory filterFactory, DocumentConsumer consumer)方法,加載配置,如下圖

 

15 最終通過以鈎子程序的形式調用函數式編程完成屬性的賦值

調用Map中的computeIfAbsent,如果不存在profile的key,則添加新的數據,並將value值返回


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM