美文网首页
Springboot配置文件读取-ConfigFileAppli

Springboot配置文件读取-ConfigFileAppli

作者: 疯子92 | 来源:发表于2019-06-24 15:35 被阅读0次

    关于

    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<String> NO_SEARCH_NAMES = Collections.singleton(null);
        private static final Bindable<String[]> 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<Profile> 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<MutablePropertySources> loaded = new ArrayList<>(this.loaded.values());
        //这里顺序颠倒下,保证了优先add的是带profile的,默认的profile是优先级最低的
        Collections.reverse(loaded);
        String lastAdded = null;
        Set<String> 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配置文件读取-ConfigFileAppli

          本文链接:https://www.haomeiwen.com/subject/vjloqctx.html