一、先搞懂:什么是配置文件的占位符?
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 写法
# 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)
# 基础配置app:name:springboot-placeholder-demoversion:1.0.0# 引用+默认值:author没定义则用「佚名」author:${app.author:佚名}# 内部复用多个占位符desc:${app.name}的版本是${app.version},运行端口是${server.port}server:port:8080场景2:给占位符设置默认值(容错兜底)
这是实际开发中必用的技巧,用于防止「配置缺失导致程序启动失败」。
比如你想让服务端口默认是8080,但若需要临时改端口,只需显式定义server.port即可,没定义就用默认值:
# 没定义server.port的话,自动用8080;定义了就用定义的值 server.port=${server.port:8080} # 自定义配置:没定义app.env的话,默认是dev(开发环境) app.env=${app.env:dev}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的内容)。
简单说:不用在配置文件写死值,能从外部动态获取,适合多环境、多机器部署的场景。
示例配置
# 引用「系统环境变量」:Windows的用户名(USERNAME)、Java安装路径(JAVA_HOME) sys.username=${USERNAME} sys.java-home=${JAVA_HOME} # 引用「命令行参数」:启动时用--app.mode=prod传参,这里就能获取 app.mode=${app.mode:test}sys:username:${USERNAME}java-home:${JAVA_HOME}app:mode:${app.mode:test}五、如何在Java代码中读取带占位符的配置?
配置文件中用占位符定义的配置,最终要在Java代码中读取使用,SpringBoot提供了2种最常用的读取方式,覆盖所有场景:
- @Value注解:适合单个/零散配置的读取,简单直接;
- @ConfigurationProperties注解:适合批量/自定义组配置的读取(如自定义的
app.xxx系列),优雅规范。
下面提供完整的Java代码示例,直接复制到项目中即可运行。
方式1:@Value注解(单个配置读取)
新建一个测试控制器,用@Value直接绑定配置项,启动项目后访问接口就能看到占位符填充后的结果:
importorg.springframework.beans.factory.annotation.Value;importorg.springframework.web.bind.annotation.GetMapping;importorg.springframework.web.bind.annotation.RestController;/** * 用@Value读取带占位符的配置 */@RestControllerpublicclassPlaceholderController{// 读取自定义配置(内部复用)@Value("${app.name}")privateStringappName;@Value("${app.desc}")privateStringappDesc;// 读取带默认值的配置@Value("${app.author}")privateStringappAuthor;// 读取系统环境变量@Value("${sys.username}")privateStringsysUsername;// 读取可通过命令行传参的配置(默认test)@Value("${app.mode}")privateStringappMode;@GetMapping("/config")publicStringgetConfig(){return"【配置读取结果】\n"+"应用名称:"+appName+"\n"+"应用描述:"+appDesc+"\n"+"作者:"+appAuthor+"\n"+"当前系统用户名:"+sysUsername+"\n"+"运行模式:"+appMode;}}方式2:@ConfigurationProperties(批量配置读取)
如果自定义的配置是一组(如app.name、app.version、app.desc都属于app组),用这种方式更优雅,无需写多个@Value。
步骤1:新建自定义配置实体类
importorg.springframework.boot.context.properties.ConfigurationProperties;importorg.springframework.stereotype.Component;/** * 批量绑定app开头的配置(前缀为app) * @Component:把这个类交给Spring管理 * @ConfigurationProperties(prefix = "app"):绑定配置中以app为前缀的所有项 */@Component@ConfigurationProperties(prefix="app")publicclassAppProperties{// 变量名要和配置中的键名一致(如app.name → name,app.version → version)privateStringname;privateStringversion;privateStringdesc;privateStringauthor;privateStringenv;privateStringmode;// 自动生成getter/setter(必须有,否则Spring无法赋值)publicStringgetName(){returnname;}publicvoidsetName(Stringname){this.name=name;}publicStringgetVersion(){returnversion;}publicvoidsetVersion(Stringversion){this.version=version;}publicStringgetDesc(){returndesc;}publicvoidsetDesc(Stringdesc){this.desc=desc;}publicStringgetAuthor(){returnauthor;}publicvoidsetAuthor(Stringauthor){this.author=author;}publicStringgetEnv(){returnenv;}publicvoidsetEnv(Stringenv){this.env=env;}publicStringgetMode(){returnmode;}publicvoidsetMode(Stringmode){this.mode=mode;}}步骤2:在控制器中注入并使用
importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.web.bind.annotation.GetMapping;importorg.springframework.web.bind.annotation.RestController;@RestControllerpublicclassAppConfigController{// 注入批量配置的实体类@AutowiredprivateAppPropertiesappProperties;@GetMapping("/app-config")publicAppPropertiesgetAppConfig(){// 直接返回实体类,Spring会自动转成JSON格式returnappProperties;}}六、运行测试(看占位符的填充效果)
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):
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(批量配置),根据实际场景选择即可。