一、先搞懂:什么是配置文件的占位符?
SpringBoot的配置文件(application.properties/application.yml)里,占位符就是用 ${变量名} 格式留的「空位置」 ,程序启动时,Spring会自动把这个「空位置」替换成实际的有效值。
可以把它理解成:配置文件里的填空题 ,${} 是填空题的空框,运行时Spring会自动给这个空框填正确的答案。
二、占位符的核心价值(为什么要用?)
- 配置复用:同一个值写一次,多处引用,避免重复编写,后续修改只需改一处,减少出错;
- 容错兜底 :可以给占位符设置默认值,如果对应的变量没定义,就用默认值,防止配置缺失报错;
- 动态配置 :能引用系统环境变量 (如电脑的
JAVA_HOME、用户名)、启动命令行参数 (如java -jar时动态传参),实现配置的动态适配。
三、占位符的核心语法
所有占位符的基础格式都是 ${xxx},扩展格式(最常用)是设置默认值:
${变量名:默认值}
- 冒号
:是分隔符,前面是要找的变量名,后面是默认值; - 如果Spring能找到
变量名对应的有效值,就用有效值; - 如果找不到(变量没定义、值为空),就用
默认值兜底。
注意 :冒号 : 后面的默认值可以省略,但若省略且变量无值,程序会启动失败(报IllegalArgumentException),所以实际开发中建议尽量加默认值。
四、典型使用场景
日常开发中,占位符主要用在3个核心场景 ,下面逐个讲解,每个场景都提供「properties + yml」两种配置文件写法(适配不同开发习惯),再搭配Java代码演示如何读取带占位符的配置。
前提:新建一个基础SpringBoot项目
只需引入最基础的spring-boot-starter-web依赖即可,用于测试配置读取。
场景1:配置文件内部变量复用(最基础、最常用)
先在配置文件中定义一个基础键值对 ,后续的其他配置通过占位符引用这个键的值,实现一次定义、多处使用。
示例配置
1.1 application.properties 写法
properties
# 1. 先定义基础配置(可被后续引用)
app.name=springboot-placeholder-demo
app.version=1.0.0
server.port=8080
# 2. 用占位符引用上面的配置(内部复用)
app.desc=${app.name}的版本是${app.version},运行端口是${server.port}
# 给个默认值的例子:如果app.author没定义,就用「佚名」
app.author=${app.author:佚名}
1.2 application.yml 写法(注意yaml的严格缩进,用2个空格,不要用tab)
yaml
# 基础配置
app:
name: springboot-placeholder-demo
version: 1.0.0
# 引用+默认值:author没定义则用「佚名」
author: ${app.author:佚名}
# 内部复用多个占位符
desc: ${app.name}的版本是${app.version},运行端口是${server.port}
server:
port: 8080
场景2:给占位符设置默认值(容错兜底)
这是实际开发中必用的技巧,用于防止「配置缺失导致程序启动失败」。
比如你想让服务端口默认是8080,但若需要临时改端口,只需显式定义server.port即可,没定义就用默认值:
properties
# 没定义server.port的话,自动用8080;定义了就用定义的值
server.port=${server.port:8080}
# 自定义配置:没定义app.env的话,默认是dev(开发环境)
app.env=${app.env:dev}
yaml
server:
port: ${server.port:8080}
app:
env: ${app.env:dev}
场景3:引用系统环境变量/启动命令行参数(动态配置)
SpringBoot会自动扫描3类值源(按优先级排序),占位符可以直接引用这些值:
- 启动时的命令行参数 (如
java -jar时加--server.port=9090); - 电脑的系统环境变量 (如Windows的
USERNAME、JAVA_HOME,Linux的USER、PATH); - 配置文件自身的变量(场景1的内容)。
简单说:不用在配置文件写死值,能从外部动态获取,适合多环境、多机器部署的场景。
示例配置
properties
# 引用「系统环境变量」:Windows的用户名(USERNAME)、Java安装路径(JAVA_HOME)
sys.username=${USERNAME}
sys.java-home=${JAVA_HOME}
# 引用「命令行参数」:启动时用--app.mode=prod传参,这里就能获取
app.mode=${app.mode:test}
yaml
sys:
username: ${USERNAME}
java-home: ${JAVA_HOME}
app:
mode: ${app.mode:test}
五、如何在Java代码中读取带占位符的配置?
配置文件中用占位符定义的配置,最终要在Java代码中读取使用,SpringBoot提供了2种最常用的读取方式,覆盖所有场景:
- @Value注解 :适合单个/零散配置的读取,简单直接;
- @ConfigurationProperties注解 :适合批量/自定义组配置 的读取(如自定义的
app.xxx系列),优雅规范。
下面提供完整的Java代码示例,直接复制到项目中即可运行。
方式1:@Value注解(单个配置读取)
新建一个测试控制器 ,用@Value直接绑定配置项,启动项目后访问接口就能看到占位符填充后的结果:
java
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* 用@Value读取带占位符的配置
*/
@RestController
public class PlaceholderController {
// 读取自定义配置(内部复用)
@Value("${app.name}")
private String appName;
@Value("${app.desc}")
private String appDesc;
// 读取带默认值的配置
@Value("${app.author}")
private String appAuthor;
// 读取系统环境变量
@Value("${sys.username}")
private String sysUsername;
// 读取可通过命令行传参的配置(默认test)
@Value("${app.mode}")
private String appMode;
@GetMapping("/config")
public String getConfig() {
return "【配置读取结果】\n" +
"应用名称:" + appName + "\n" +
"应用描述:" + appDesc + "\n" +
"作者:" + appAuthor + "\n" +
"当前系统用户名:" + sysUsername + "\n" +
"运行模式:" + appMode;
}
}
方式2:@ConfigurationProperties(批量配置读取)
如果自定义的配置是一组 (如app.name、app.version、app.desc都属于app组),用这种方式更优雅,无需写多个@Value。
步骤1:新建自定义配置实体类
java
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* 批量绑定app开头的配置(前缀为app)
* @Component:把这个类交给Spring管理
* @ConfigurationProperties(prefix = "app"):绑定配置中以app为前缀的所有项
*/
@Component
@ConfigurationProperties(prefix = "app")
public class AppProperties {
// 变量名要和配置中的键名一致(如app.name → name,app.version → version)
private String name;
private String version;
private String desc;
private String author;
private String env;
private String mode;
// 自动生成getter/setter(必须有,否则Spring无法赋值)
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String getVersion() { return version; }
public void setVersion(String version) { this.version = version; }
public String getDesc() { return desc; }
public void setDesc(String desc) { this.desc = desc; }
public String getAuthor() { return author; }
public void setAuthor(String author) { this.author = author; }
public String getEnv() { return env; }
public void setEnv(String env) { this.env = env; }
public String getMode() { return mode; }
public void setMode(String mode) { this.mode = mode; }
}
步骤2:在控制器中注入并使用
java
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class AppConfigController {
// 注入批量配置的实体类
@Autowired
private AppProperties appProperties;
@GetMapping("/app-config")
public AppProperties getAppConfig() {
// 直接返回实体类,Spring会自动转成JSON格式
return appProperties;
}
}
六、运行测试(看占位符的填充效果)
1. 直接启动项目(无命令行参数)
启动后访问 http://localhost:8080/config,会看到所有占位符都被自动填充,效果如下:
【配置读取结果】
应用名称:springboot-placeholder-demo
应用描述:springboot-placeholder-demo的版本是1.0.0,运行端口是8080
作者:佚名
当前系统用户名:你的电脑用户名(如Administrator)
运行模式:test
访问 http://localhost:8080/app-config,会看到JSON格式的批量配置结果,占位符同样被填充。
2. 带命令行参数启动(动态修改配置)
把项目打成jar包(mvn clean package),用以下命令启动(动态传参--app.mode=prod、--server.port=9090):
bash
java -jar 你的项目包名.jar --app.mode=prod --server.port=9090
启动后访问 http://localhost:9090/config,会看到命令行参数覆盖了默认值:
运行模式:prod (不再是默认的test)
应用描述:...运行端口是9090 (不再是8080)
七、开发中常见的「小坑」避坑
- yaml配置的缩进问题 :yaml对缩进严格,必须用2个空格,不能用tab,否则配置读取失败;
- 默认值的冒号后空格 :yaml中
${key:默认值}的冒号后可以有空格 (如${app.mode: test}),properties中不能有空格 (如${app.mode:test},加空格会把空格当成默认值的一部分); - 占位符嵌套 :SpringBoot支持占位符嵌套(如
${app.desc:${app.name}默认描述}),但尽量少用,避免配置可读性变差; - @ConfigurationProperties必须有getter/setter :Spring通过反射赋值,没有getter/setter会导致变量值为
null。
八、总结
- SpringBoot配置文件占位符的基础格式 是
${变量名},带默认值的格式 是${变量名:默认值},冒号是分隔符; - 占位符的核心作用是配置复用、容错兜底、动态配置,是日常开发中提高配置灵活性的必备技巧;
- 占位符可以引用配置文件内部变量、系统环境变量、命令行参数,Spring会自动按优先级查找有效值;
- 读取带占位符的配置有两种方式:
@Value(单个配置)、@ConfigurationProperties(批量配置),根据实际场景选择即可。