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