Springboot配置文件读取-ConfigFileApplicationListener

关于

ConfigFileApplicationListener主要作用就是读取应用的配置文件并add到Environment的PropertySources列表里

Springboot应用在启动的时候准备好了环境后就会触发ApplicationEnvironmentPreparedEvent事件就开始执行读取配置的逻辑:


首先加载当前激活的Profile列表

然后从默认的classpath:/,classpath:/config/,file:./,file:./config/这四个目录下

查找默认的application-{profile}名字对应的配置文件,配置文件格式支持两大类(Properties和Yaml)既:.properties .xml .yml .yaml

涉及到的配置参数

  • spring.config.name
  • spring.config.location
  • spring.profiles.active
  • spring.profiles.include
  • spring.config.additional-location

spring.config.name

可以修改默认的配置文件名字(默认:application),可以指定多个比如 --spring.config.name= application,demo

spring.config.location

可以修改默认的配置文件路径,比如 --spring.config.location= file:///C:/config/ (目录结尾不带“/”会按照文件处理,而不是目录,容易掉坑)

源码阅读收获

通过类的的常量大概知道有什么属性支持配置以及默认参数

    //Note the order is from least to most specific (last one wins)
    private static final String DEFAULT_SEARCH_LOCATIONS = "classpath:/,classpath:/config/,file:./,file:./config/";
    private static final String DEFAULT_NAMES = "application";
    private static final Set NO_SEARCH_NAMES = Collections.singleton(null);
    private static final Bindable STRING_ARRAY = Bindable.of(String[].class);
    public static final String ACTIVE_PROFILES_PROPERTY = "spring.profiles.active";
    public static final String INCLUDE_PROFILES_PROPERTY = "spring.profiles.include";
    public static final String CONFIG_NAME_PROPERTY = "spring.config.name";
    public static final String CONFIG_LOCATION_PROPERTY = "spring.config.location";
    public static final String CONFIG_ADDITIONAL_LOCATION_PROPERTY = "spring.config.additional-location";

它既是一个ApplicationListener,也是一个EnvironmentPostProcessor

阅读源码入口就从他的onApplicationEvent开始跟即可,将自身添加到postProcessor列表里并执行postProcessEnvironment方法,核心逻辑是靠一个Loader内部类
new Loader(environment, resourceLoader).load()

load()方法大概骨架逻辑

public void load() {
   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 (profile != null && !profile.isDefaultProfile()) {
           addProfileToEnvironment(profile.getName());
       }
       load(profile, this::getPositiveProfileFilter, addToLoaded(MutablePropertySources::addLast, false));
       this.processedProfiles.add(profile);
   }
   resetEnvironmentProfiles(this.processedProfiles);
   load(null, this::getNegativeProfileFilter, addToLoaded(MutablePropertySources::addFirst, true));
   addLoadedPropertySources();
}

initializeProfiles() 加载所有可能的profiles

private void initializeProfiles() {
    // The default profile for these purposes is represented as null. We add it
    // first so that it is processed first and has lowest priority.
    this.profiles.add(null);
    Set activatedViaProperty = getProfilesActivatedViaProperty();
    this.profiles.addAll(getOtherActiveProfiles(activatedViaProperty));
    // Any pre-existing active profiles set via property sources (e.g.
    // System properties) take precedence over those added in config files.
    addActiveProfiles(activatedViaProperty);
    if (this.profiles.size() == 1) { // only has null profile
        for (String defaultProfileName : this.environment.getDefaultProfiles()) {
            Profile defaultProfile = new Profile(defaultProfileName, true);
            this.profiles.add(defaultProfile);
        }
    }
}

大概就是,如果没有spring.profiles.active 和 spring.profiles.include都没有特别指定激活的profile的话

没有特别指定profile的话就是:null + default,也就是我们常见的application.properties 和 application-default.properties这种

如果指定了那就是:null + 已经激活(pre-existing)的profile + spring.profiles.active + spring.profiles.include

addLoadedPropertySources() 保证了 application-{profile}里的会覆盖不带profile的配置

private void addLoadedPropertySources() {
    MutablePropertySources destination = this.environment.getPropertySources();
    List loaded = new ArrayList<>(this.loaded.values());
    //这里顺序颠倒下,保证了优先add的是带profile的,默认的profile是优先级最低的
    Collections.reverse(loaded);
    String lastAdded = null;
    Set added = new HashSet<>();
    for (MutablePropertySources sources : loaded) {
        for (PropertySource source : sources) {
            if (added.add(source.getName())) {
                addLoadedPropertySource(destination, lastAdded, source);
                lastAdded = source.getName();
            }
        }
    }
}

举个例子,假如激活了多个profile比如:--spring.profiles.active=prd1,prd2,最终优先级上prd1 > prd2 > default(null)

你可能感兴趣的:(Springboot配置文件读取-ConfigFileApplicationListener)