文章目录
前言
Spring Boot 在工作中是用到的越来越广泛了,简单方便,有了它,效率提高不知道多少倍。Spring Boot 配置文件对 Spring Boot 来说就是入门和基础,经常会用到。下面话不多说了,来一起看看详细的介绍吧。
Spring Boot 配置文件概述
当我们新建一个 Springboot 项目之后,会在 resources 目录下给我们一个默认的全局配置文件 application.properties,这是一个空文件,因为 Spring Boot 在底层已经把配置都给我们自动配置好了,当在配置文件进行配置时,会修改 SpringBoot 自动配置的默认值。
配置文件名是固定的 application.properties 或者 application.yml。当然有时候一个配置文件是不能满足我们的需求,我们可能会配置多个,这个时候我们可以修改后缀来区分不同的配置文件 ,比如 application-dev.properties。还可以通过 spring.config.name 来直接修改配置文件前缀名称。
- 配置文件格式:
application-{profile}.properties/yml
- 自定义名称可使用参数:
--spring.config.name=customname
- properties:键值形式,格式要求不是很高,结构不清晰。
- yml:树状结构,格式要求比较严格,结构清晰。
一个项目部署时,SpringBoot 的配置文件应该放在哪?加载顺序是什么呢?
工程根目录:./config/
工程根目录:./
classpath:/config/
classpath:/
注:application-profile 优先于 application。
优先级顺序是从上向下加载(优先级从高到低),所有的文件都会被加载,高优先级的内容会覆盖低优先级的内容,形成互补配置。
多配置文件加载特性
正常的开发中会有多个环境,测试环境,开发环境,生产环境等。无论采用 properties 还是 yml,都可以根据不同的使用环境来指定使用具体环境的配置文件。各环境配置文件名称 application-{profile}.properties/yml,即前面提到的。举例:
- application-dev.properties:开发环境配置文件
- application-test.properties:测试环境配置文件
- application-pro.properties:生产环境配置文件
如果这三个都放在项目下,那我们如何判断各个环境应该加载哪个配置文件呢,这时我们便可以用如下参数来按需加载。
--spring.profiles.active=dev
当 application.properties 和 yml 文件在并存时(同一目录下),application.properties 优先级更好,会先读它,若它没有,再去读 yml 中的值。
当配置文件和项目部署路径不一致时,可通过参数来指定配置文件位置。
--spring.config.location=path
ApplicationEnvironmentPreparedEvent 事件之重置配置文件加载位置
问题一:现在有一种需求,一个项目配置项很多,不过可以拆分为两类,一类是程序默认配置一般不需要改动,一类是用户自定义配置。那这个时候我们怎么办呢?而且一般程序都是交由实施去部署的,而实施对 yml 格式把握不是很好,部署时很容易出现错误而且很难发现。导致程序起不来让人头疼,这又怎么解决呢?
解决:我们是否可以用上面所说的 yml 和 properties 同时配置呢?yml 对程序员来说比较符合书写规范,properties 对实施人员来说比较容易上手,没有特别的格式要求,即使多一个空格也无足轻重。而 yml 却不同。
于是有了我们的设计方案,程序配置分为两类,application.yml 和 application.properties。yml 里面是程序默认配置,pro 里面是自定义的配置。前面也说到这两个是可以共存的,而且是互补配置,也就是说 properties 里面配置自定义参数的可以覆盖 yml 里面的同名键的默认配置。这样就解决了这个问题。
问题二: 这里还有一个问题,当两个文件放在程序下的同一个位置,比如 classpath:/config/
下,那加载自然是没问题的,要是我这个自定义的 application.properties 不想放在程序里面,而想放在服务器上的任意一个位置呢,这怎么解决?
你肯定会想到用 --spring.config.location
来加载。但是如果你写了这个参数,SpringBoot 是加载不到默认的 yml 配置文件的。当然我们也可以用 --spring.config.location
把自定义和程序默认的位置都一起指定。比如:
--spring.config.location=/opt/work/tomcat8/webapps/application.properties,classpath:/config/application.yml
这样也是可以同时加载这里个配置文件的。
但是路径太长了,我们不想配置,那就得去看下源码了。
可以看到这里其实所有的配置文件路径最终会被存到一个 Set 里面,这里有顺序的问题,路径会被逆转顺序。也就是说配置在前面的优先级低。这是需要注意的。
看到这,我们是否可以监听一个事件,去改变这个 spring.configs.location 的值呢,毕竟 yml 在程序包中的位置一直是固定的,我不想每次都配置。是有的,就是 ApplicationEnvironmentPreparedEvent。话不多说,直接上代码吧。
/**
* 重置配置文件加载位置
* 这里为啥有两个 reset 方法呢,因为我们配置 spring.config.location 有两种方式,
* 一种配置 program 参数 --spring.config.location=path
* 另外一种配置 vm 参数:-Dspring.config.location=path
*
*/
@Component
public class CustomConfigApplicationListener implements ApplicationListener<ApplicationEnvironmentPreparedEvent>,Ordered {
private static Logger logger=LoggerFactory.getLogger(CustomConfigApplicationListener.class);
private static final int DEFAULT_ORDER = Ordered.HIGHEST_PRECEDENCE +9;
private static final String CONFIG_LOCATION_PROPERTY = "spring.config.location";
@Override
public void onApplicationEvent(ApplicationEnvironmentPreparedEvent event) {
if (event instanceof ApplicationEnvironmentPreparedEvent) {
ConfigurableEnvironment envi = event.getEnvironment();
MutablePropertySources prpoSource = envi.getPropertySources();
StringBuffer config = new StringBuffer("--");
config.append(CONFIG_LOCATION_PROPERTY);
config.append("=classpath:\\config\\");
resetCommonLineArgs(prpoSource, config);
resetSystemProperties(prpoSource, config);
}
}
private void resetCommonLineArgs(MutablePropertySources propSource, StringBuffer config) {
PropertySource<?> commandLineArgs = propSource.get("commandLineArgs");
if (null != commandLineArgs) {
String defaultLocation = commandLineArgs.getProperty(CONFIG_LOCATION_PROPERTY) != null
? (String) commandLineArgs.getProperty(CONFIG_LOCATION_PROPERTY)
: null;
if (null != defaultLocation) {
config.append(",");
config.append(defaultLocation);
logger.info("加载配置文件:"+config.toString().substring(config.indexOf("=")+1));
PropertySource<?> newEnv = new SimpleCommandLinePropertySource(config.toString());
propSource.addFirst(newEnv);
}
}
}
@SuppressWarnings("unchecked")
private void resetSystemProperties(MutablePropertySources propSource, StringBuffer config) {
PropertySource<?> systemProperties = propSource.get("systemProperties");
if (null != systemProperties) {
Map<String, Object> pro = (Map<String, Object>) systemProperties.getSource();
String defaultConfig = pro.get(CONFIG_LOCATION_PROPERTY) != null
? (String) pro.get(CONFIG_LOCATION_PROPERTY)
: null;
if (null != defaultConfig) {
config.append(",");
config.append(defaultConfig);
pro.put(CONFIG_LOCATION_PROPERTY, config.substring(config.indexOf("=")+1).toString());
logger.info("加载配置文件:"+defaultConfig);
MapPropertySource mapPropertySource = new MapPropertySource("systemProperties", pro);
propSource.addBefore("systemEnvironment", mapPropertySource);
}
}
}
@Override
public int getOrder() {
return DEFAULT_ORDER;
}
}
这样我们就实现了配置文件同时加载 yml 和 properties,并且 properties 可以放在任意位置。可以直接在 tomcat 中配置文件位置。
扩展
当需要配置多个自定义文件时,可以使用如下参数在主配置文件中引入其他配置文件:
--spring.profiles.include=redis,mysql
这里的 redis 和 mysql 是文件后缀名。
以上如有不对,见谅。再会!
更多可参考: