【Spring Boot】(7)、配置文件加载位置

Spring Boot启动会扫描以下位置的application.properties/yml文件作为Spring Boot默认配置文件:

Spring Boot官方文档章节:加载application.properties配置文件

  • 外置,在相对于应用程序运行目录的/config子目录里

  • 外置,在应用程序运行的目录里

  • 内置,在resources/config包内

  • 内置,在classpath根目录(resouces目录下)


源码解析

ConfigFileApplicationListener.class

public class ConfigFileApplicationListener
		implements EnvironmentPostProcessor, SmartApplicationListener, Ordered {

    //...
    
    //默认配置文件名
    private static final String DEFAULT_NAMES = "application";

    // 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/";
    
    public static final String CONFIG_LOCATION_PROPERTY = "spring.config.location";
    
    public static final String CONFIG_NAME_PROPERTY = "spring.config.name";
    
    //...
}

ConfigFileApplicationListener.load()

public void load() {
        this.propertiesLoader = new PropertySourcesLoader();
        this.activatedProfiles = false;
        this.profiles = Collections.asLifoQueue(new LinkedList<Profile>());
        this.processedProfiles = new LinkedList<Profile>();

        //上节讲述过,会获取当前profiles激活的环境,默认为default
        Set<Profile> initialActiveProfiles = initializeActiveProfiles();
        this.profiles.addAll(getUnprocessedActiveProfiles(initialActiveProfiles));
        if (this.profiles.isEmpty()) {
            for (String defaultProfileName : this.environment.getDefaultProfiles()) {
                Profile defaultProfile = new Profile(defaultProfileName, true);
                if (!this.profiles.contains(defaultProfile)) {
                    this.profiles.add(defaultProfile);
                }
            }
        }

        this.profiles.add(null);

        while (!this.profiles.isEmpty()) {
            Profile profile = this.profiles.poll();
            //获取配置文件的查找路径
            for (String location : getSearchLocations()) {
                if (!location.endsWith("/")) {
                    // location is a filename already, so don't search for more
                    // filenames
                    load(location, null, profile);
                }
                else {
                    for (String name : getSearchNames()) {
                        load(location, name, profile);
                    }
                }
            }
            this.processedProfiles.add(profile);
        }

        addConfigurationProperties(this.propertiesLoader.getPropertySources());
    }

ConfigFileApplicationListener.getSearchLocations()

private Set<String> getSearchLocations() {
    Set<String> locations = new LinkedHashSet<String>();
    //用户自定义的配置文件,优先加载,通过spring.config.location指定
    if (this.environment.containsProperty(CONFIG_LOCATION_PROPERTY)) {
        for (String path : asResolvedSet(
            this.environment.getProperty(CONFIG_LOCATION_PROPERTY), null)) {
            if (!path.contains("$")) {
                path = StringUtils.cleanPath(path);
                if (!ResourceUtils.isUrl(path)) {
                    path = ResourceUtils.FILE_URL_PREFIX + path;
                }
            }
            locations.add(path);
        }
    }
    
    //获取查找路径
    locations.addAll(
        asResolvedSet(ConfigFileApplicationListener.this.searchLocations,
                      DEFAULT_SEARCH_LOCATIONS));
    return locations;
}

ConfigFileApplicationListener.asResolvedSet()

private Set<String> asResolvedSet(String value, String fallback) {
    List<String> list = Arrays.asList(StringUtils.trimArrayElements(
        StringUtils.commaDelimitedListToStringArray(value != null
                                                    ? this.environment.resolvePlaceholders(value) : fallback)));
    //将元素进行反转,所以查找的路径实际跟DEFAULT_SEARCH_LOCATIONS所定义的顺序刚好相反。
    Collections.reverse(list);
    return new LinkedHashSet<String>(list);
}

ConfigFileApplicationListener.getSearchNames()

private Set<String> getSearchNames() {
    //如果环境中有以spring.config.name的配置,则以该值作为配置文件名
    if (this.environment.containsProperty(CONFIG_NAME_PROPERTY)) {
        return asResolvedSet(this.environment.getProperty(CONFIG_NAME_PROPERTY),
                             null);
    }
	//获取默认的配置文件名,默认为application
    return asResolvedSet(ConfigFileApplicationListener.this.names, DEFAULT_NAMES);
}

PropertySourcesLoader.getAllFileExtensions()

public Set<String> getAllFileExtensions() {
    Set<String> fileExtensions = new LinkedHashSet<String>();
    //获取所有配置文件的后缀名,分别是properties,xml,yml,yaml
    for (PropertySourceLoader loader : this.loaders) {
        fileExtensions.addAll(Arrays.asList(loader.getFileExtensions()));
    }
    return fileExtensions;
}

所以其实Spring Boot支持四种配置文件格式:

  • properties

  • xml

  • yml

  • yaml

    而xml用的少,yml和yaml其实是一样的格式,所以常用的是properties和yml。


PropertySourcesLoader.doLoadIntoGroup()

private PropertySource<?> doLoadIntoGroup(String identifier, String location,
				Profile profile) throws IOException {
    Resource resource = this.resourceLoader.getResource(location);
    PropertySource<?> propertySource = null;
    StringBuilder msg = new StringBuilder();
    if (resource != null && resource.exists()) {
        String name = "applicationConfig: [" + location + "]";
        String group = "applicationConfig: [" + identifier + "]";
        propertySource = this.propertiesLoader.load(resource, group, name,
                                                    (profile == null ? null : profile.getName()));
        if (propertySource != null) {
            msg.append("Loaded ");
            handleProfileProperties(propertySource);
        }
        else {
            msg.append("Skipped (empty) ");
        }
    }
    else {
        msg.append("Skipped ");
    }
    msg.append("config file ");
    msg.append(getResourceDescription(location, resource));
    if (profile != null) {
        msg.append(" for profile ").append(profile);
    }
    if (resource == null || !resource.exists()) {
        msg.append(" resource not found");
        this.logger.trace(msg);
    }
    else {
        this.logger.debug(msg);
    }
    return propertySource;
}

总结

  • 分别从file:./config/, file:./, classpath:/config/, classpath:/ 这四个位置依次读取后缀名为properties, xml, yml, yaml的配置文件

  • 优先级由高到低,对于相同的属性配置,高优先级的配置会覆盖优先级低的配置;对于其他不同的属性配置,则会进行互补。

  • 优先级相同的情况下,同时有application.properties和application.yml,那么application.properties里面的属性就会覆盖application.yml里的属性,因为properties比yml优先加载。

​在查看源码的时候,在getSearchLocations()代码中,提示可以通过spring.config.location来改变默认的配置文件位置:项目打包好以后,使用命令行参数的形式--spring.config.location=…来启动项目,用来指定配置文件的新位置,从而使指定的新配置文件和包内的默认加载的配置文件共同起作用行程互补配置。

1java -jar spring-boot-02-config-SNAPSHOT.jar --spring.config.location=F

博主在写这篇博文前,遇到一个无法解决的问题,见链接:SpringBoot加载配置文件优先级问题


====================打个广告,欢迎关注====================

QQ:
412425870
微信公众号:Cay课堂

csdn博客:
http://blog.csdn.net/caychen
码云:
https://gitee.com/caychen/
github:
https://github.com/caychen

点击群号或者扫描二维码即可加入QQ群:

328243383(1群)




点击群号或者扫描二维码即可加入QQ群:

180479701(2群)




猜你喜欢

转载自blog.csdn.net/caychen/article/details/79980415