SpringBoot2.x入门教程:理解配置文件
前提
这篇文章是《SpringBoot2.x入门》专辑的第4篇文章,使用的SpringBoot
版本为2.3.1.RELEASE
,JDK
版本为1.8
。
主要介绍SpringBoot
配置文件一些常用属性、配置文件的加载优先级以及一些和配置相关的注意事项。
关于SpringBoot的配置文件
一个基于标准的引入了SpringBoot
组件的Maven
项目的结构一般如下:
Root(项目根目录)
- src
- main
- java
- resources # <-- 这个就是资源文件的存放目录
- target
pom.xml
资源文件存放在src/main/resouces
目录下,而配置文件本质上也是资源文件,所以项目内的配置文件就存放于该目录下。从SpringBoot
的属性源加载器PropertySourceLoader
的实现来看,目前支持Properties
和Yaml
两种配置文件类型。两者各有优势:Yaml
的配置属性更灵活,而Properties
的配置不容易出错(笔者前公司的技术规范中明确了SpringBoot
应用必须使用Properties
配置文件,因为运维或者开发同事曾因为生产配置使用了Yaml
格式的文件,编辑期间因为空格问题导致了严重的生产故障)。下文会使用Properties
配置文件作为示例。
SpringBoot
的配置文件使用了profile
(profile
本身就有剖面、配置文件的含义,下面会把profile
作为一个专有名词使用)的概念,可以类比为区分不同环境的标识符,一个SpringBoot
应用允许使用多个profile
,所以配置文件的格式必须为application-${profile}.文件后缀
,例如:
src/main/resources
- application.properties
- application-dev.properties # <-- profile = dev,开发环境配置
- application-test.properties # <-- profile = test,测试环境配置
其中不带profile
标识的application.properties
,可以理解为主配置文件,也就是SpringBoot
的配置文件其实有继承关系,项目启动时,主配置文件无论如何都会优先加载,然后被激活的profile
标识的配置文件才会加载,可以通过属性spring.profiles.active
指定激活哪一个profile
配置文件,如:
# 指定加载application-dev.properties
spring.profiles.active=dev
# 或者同时加载application-dev.properties和application-test.properties
spring.profiles.active=dev,test
spring.profiles.active
一般可以在主配置文件application.properties
中指定,获取通过启动命令参数指定(java -jar -Dspring.profiles.active=prod app.jar
或者java -jar app.jar --spring.profiles.active=prod
)。
可以通过自动装配org.springframework.core.env.Environment
,通过Environment#getActiveProfiles()
获取当前激活的profile
数组,例如:
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.core.env.Environment;
import java.util.Arrays;
@Slf4j
@SpringBootApplication
public class Ch2Application implements CommandLineRunner {
@Autowired
private Environment environment;
public static void main(String[] args) {
SpringApplication.run(Ch2Application.class, args);
}
@Override
public void run(String... args) throws Exception {
log.info("Active profiles:{}", Arrays.toString(environment.getActiveProfiles()));
}
}
运行结果如下:
这里用到了CommandLineRunner
接口作为展示,后面的文章会介绍该接口的使用方式。
常用的基本配置属性
一般情况下会引入spring-boot-starter-web
开发web
项目,有几个基本配置笔者认为是必须的。主配置文件application.properties
中应该标识应用名和默认选用的profile
,例如API
网关的主配置文件如下:
spring.application.name=api-gateway
spring.profiles.active=dev
此外,主配置中间中应该配置一些不容易变动的属性,例如Mybatis
的Mapper
扫描路径、模板引擎Freemarker
的配置属性等等。而profile
标识的配置文件中,应该配置一些跟随环境变化的配置或者经常更变的属性,例如MySQL
数据源的配置、Redis
的连接配置等等,以便通过spring.profiles.active
直接切换不同环境的中间件连接属性或者第三方配置。在Hello World
类型的项目中,一般添加server.port
指定容器的启动端口,如application-dev.properties
的内容如下:
server.port=8081
配置文件加载优先级与属性覆盖
除了主配置文件会优先profile
标识的配置文件加载之外,SpringBoot
还支持通过文件系统加载配置文件,这些配置文件不一定在项目内(准确来说是项目编译之后打出来的包内),还可以存在于特定的磁盘路径中。这一点可以参考SpringBoot
官方文档2.Externalized Configuration
一节:
默认的配置文件加载优先级顺序是:
file:./config/
(项目部署包所在目录的同级config
目录下的application-[profile].[properties,yaml]
文件)file:./config/*/
(项目部署包所在目录的同级config
目录下的任意子目录中的application-[profile].[properties,yaml]
文件)file:./
(项目部署包所在目录的application-[profile].[properties,yaml]
文件)classpath:/config/
(项目部署包内类路径下的config
目录下的application-[profile].[properties,yaml]
文件)classpath:/
(项目部署包内类路径下的application-[profile].[properties,yaml]
文件)
眼尖的伙伴可能会发现,在项目中的resources
目录下添加的配置文件的加载优先级是最低的(打包后相当于第5条)。可以通过spring.config.location
属性覆盖上面的顺序,如spring.config.location=classpath:/,classpath:/config/
,一般不建议改变默认的配置顺序,除非有特殊的使用场景。
另外,还可以通过spring.config.additional-location
属性指定额外附加的搜索配置文件的路径,并且优先级比默认的配置顺序要高,假如只配置了spring.config.additional-location=classpath:/custom-config/,file:./custom-config/
,那么配置文件加载优先级顺序是:
file:./custom-config/
(项目部署包所在目录的同级custom-config
目录下的application-[profile].[properties,yaml]
文件)classpath:custom-config/
(项目部署包内类路径下的custom-config
目录下的application-[profile].[properties,yaml]
文件)file:./config/
(项目部署包所在目录的同级config
目录下的application-[profile].[properties,yaml]
文件)file:./config/*/
(项目部署包所在目录的同级config
目录下的任意子目录中的application-[profile].[properties,yaml]
文件)file:./
(项目部署包所在目录的application-[profile].[properties,yaml]
文件)classpath:/config/
(项目部署包内类路径下的config
目录下的application-[profile].[properties,yaml]
文件)classpath:/
(项目部署包内类路径下的application-[profile].[properties,yaml]
文件)
基于这个特性,在不对接配置中心的前提下,可以让运维伙伴在生产服务器上先配置好服务所需的生产环境的配置文件:
# 假设这个是生产服务器的文件路径
/data/apps/api-gateway
- api-gateway.jar
- config
- application-prod.properties
在编写启动脚本的时候只需指定profile
为prod
即可,应用会读取/data/apps/api-gateway/config/application-prod.properties
的属性,这样就能避免生产配置或者敏感属性泄漏给开发人员。
这里还有一个比较重要的问题就是:如果在多种路径下的配置文件定义了同一个属性,那么属性会依照一个优先级顺序进行覆盖。因为SpringBoot
除了配置文件,还支持命令行、JNDI
属性、系统属性等等,如果全部列举会比较复杂,这里按照目前分析过的内容列举这个优先级顺序:
- 命令行中的属性参数。
- 项目部署包之外的
application-profile.[properties,yaml]
文件。 - 项目部署包内的
application-profile.[properties,yaml]
文件。 - 项目部署包之外的
application.[properties,yaml]
文件。 - 项目部署包内的
application.[properties,yaml]
文件。
举个例子,假如启动参数中添加--app.author=throwable
,配置文件application.properties
中添加属性app.author=throwable-x
,而配置文件application-dev.properties
中添加属性app.author=throwable-y
,那么使用profile=dev
启动应用的时候,优先获取到的是属性app.author=throwable
:
如果看过SpringBoot属性加载的源码可知,其实属性优先级的思路在设计属性加载模块的时候正好相反,所有的配置文件都会进行解析,构成一个复合的PropertySource,后解析的参数总是在顶层,然后获取属性的时候,总是先从顶层获取。
自定义配置属性与IDE亲和性
有时候需要配置自定义属性,会出现在IDE
中会无法识别而"标黄"的场景。这个时候可以应用IDE
亲和性。在主流的IDE
如Eclipse
和IntelliJ IDEA
中,只需要引入SpringBoot
的属性元数据描述文件(spring-configuration-metadata.json
或者additional-spring-configuration-metadata.json
),即可让IDE
识别,提供目录引导跳转的功能,不再"标黄"。具体的做法是在项目的resources/META-INF
目录中引入属性元数据描述文件,然后编写属性描述即可:
// resources/META-INF/spring-configuration-metadata.json
{
"properties": [
{
"name": "app.author",
"type": "java.lang.String",
"description": "The author of app."
}
]
}
spring-configuration-metadata.json
文件的格式可以参考SpringBoot
多个starter
中已经存在的文件,完成这一点,代码洁癖患者或者强迫症患者会感觉良好。
小结
这篇文章简单总结了配置文件加载的优先级顺序和配置属性的覆盖优先级顺序,这两点需要完全掌握,可以自行通过一些例子改变一下配置文件进行熟悉。配置属性覆盖的问题很容易导致生产故障,如果掌握了本节的内容,对于SpringBoot
配置属性方面的问题应该可以快速定位和解决。代码仓库:
(本文完 c-2-d e-a-20200705)
技术公众号《Throwable文摘》(id:throwable-doge),不定期推送笔者原创技术文章(绝不抄袭或者转载):
SpringBoot2.x入门教程:理解配置文件的更多相关文章
- SpringBoot2.x入门教程:引入jdbc模块与JdbcTemplate简单使用
这是公众号<Throwable文摘>发布的第23篇原创文章,收录于专辑<SpringBoot2.x入门>. 前提 这篇文章是<SpringBoot2.x入门>专辑的 ...
- WCF入门教程(五)配置文件
WCF入门教程(五)配置文件 服务协定以及实现写好后,需要将相关服务公布出去,就需要HOST来承载,供客户端来调用. 承载服务有两种方式,一种通过配置文件,一种通过代码进行配置.上一章已经介绍了代码方 ...
- emacs 入门教程,菜单汉化,配置文件等杂乱文章
首先来一发ArchWiki的Emacs简体中文的入门教程 https://wiki.archlinux.org/index.php/Emacs_(%E7%AE%80%E4%BD%93%E4%B8%AD ...
- D3.js的v5版本入门教程(第四章)—— 理解Update、Enter、Exit
D3.js的v5版本入门教程(第四章) Update.Enter.Exit是D3.js中很重要的概念,下面来讲一下它们到底是什么?(当你看完后.你就会知道如果数据集个数和选择集个数不匹配的情况下使用d ...
- 21分钟 MySQL 入门教程(转载!!!)
21分钟 MySQL 入门教程 目录 一.MySQL的相关概念介绍 二.Windows下MySQL的配置 配置步骤 MySQL服务的启动.停止与卸载 三.MySQL脚本的基本组成 四.MySQL中的数 ...
- kafka入门教程链接
http://www.aboutyun.com/forum.php?mod=viewthread&tid=12882 经典入门教程 1.Kafka独特设计在什么地方?2.Kafka如何搭建及创 ...
- Laravel 5 系列入门教程(一)【最适合中国人的 Laravel 教程】
Laravel 5 系列入门教程(一)[最适合中国人的 Laravel 教程] 分享⋅ johnlui⋅ 于 2年前 ⋅ 最后回复由 skys215于 11个月前 ⋅ 17543 阅读 原文发表在 ...
- Laravel 4 系列入门教程(一)
默认条件 本文默认你已经有配置完善的PHP+MySQL运行环境,懂得PHP网站运行的基础知识.跟随本教程走完一遍,你将会得到一个基础的包含登录的简单blog系统,并将学会如何使用一些强大的Larave ...
- 【军哥谈CI框架】之入门教程之第二讲:分析CI结构和CI是怎么工作的
[军哥谈CI框架]之入门教程之第二讲:分析CI结构和CI是怎么工作的 之入门教程之第二讲:分析CI结构和CI是如何工作的大家好!上一节,我们共同部署了一个CI网站,做到这一点非常简单,但是,亲们, ...
随机推荐
- Java实现第八届蓝桥杯购物单
购物单 题目描述 小明刚刚找到工作,老板人很好,只是老板夫人很爱购物.老板忙的时候经常让小明帮忙到商场代为购物.小明很厌烦,但又不好推辞. 这不,XX大促销又来了!老板夫人开出了长长的购物单,都是有打 ...
- java实现第七届蓝桥杯搭积木
搭积木 题目描述 小明最近喜欢搭数字积木, 一共有10块积木,每个积木上有一个数字,0~9. 搭积木规则: 每个积木放到其它两个积木的上面,并且一定比下面的两个积木数字小. 最后搭成4层的金字塔形,必 ...
- mysql基础之-mysql存储引擎概述(八)
0x01 mysql 存储引擎:存储引擎也通常被称作“表类型” mysql> show engines; --- 查看当前所有所支持的存储引擎 mysql> show table st ...
- Python常用推导式
列表推导式: #列表推导式 #基本格式[] # 变量 = [for循环的变量 for循环一个可迭代对象] # 变量 = [i for i in 可迭代对象 if 条件] 条件为true才进行appen ...
- 关于echart的x轴固定为0-24小时显示一天内的数据
需求: echart折线图横坐标x轴固定显示为0-1-2-3-...-23-24一共24小时的数据. 根据需求,我在网上以及echart官网,发现x轴无论type是类目轴还是时间,都是自动处理的,尤其 ...
- vue踩过的坑('url' is assigned a value but never used no-unused-vars)
1.代码编写 2.遇见错误 3.解决方案 在错误代码后加入注释:(// eslint-disable-line no-unused-vars) 之后页面上就不会出现该错误信息了
- D2大全
年初看到cnblogs上有人说看这本旧书,自己也只是瞟了下,后来在看些OOP东西时,想想没事也看看老古董,于是网购了一本电子版可参考下,它们是怎么一步步来,还没来得及多看,贴图于此.
- PAI-AutoLearning 图像分类使用教程
概述 PAI AutoLearning(简称PAI AL)自动学习支持在线标注.自动模型训练.超参优化以及模型评估.在平台上只需准备少量标注数据,设置训练时长即可得到深度优化的模型.同时自动学习PAI ...
- HTMLTestRunner生成html测试报告
使用:把文件放到项目某个文件夹中,引入方式如下 import unittest import env import vendor.report.HTMLTestRunnerNew as HTMLTes ...
- Java8新特性之函数式接口
<Java 8 实战>学习笔记系列 定义 函数式接口只定义一个抽象方法,可以有多个默认方法 函数式接口的接口名上,会被@FunctionalInterface标注 作用 函数式接口的方法可 ...