CodeRoad Map 程序员的学习成长路线图。内容免费开放,登录后可同步路线图与课时进度。
由 程序员柏风 独立维护 · 关于作者
学习 更多
配置与 Profile
这一课你将能做到
用 yml 组织项目配置,并用 @Value 和 @ConfigurationProperties 两种方式注入到代码
建立 dev / prod 多环境配置,用三种方式(yml、命令行、环境变量)切换 Profile
说清 Spring Boot 配置的优先级顺序,并用环境变量管理数据库密码等敏感信息
为什么要学
同一套代码,本地连 H2、测试连测试库、生产连生产库,端口、日志级别、第三方密钥全都不一样。配置与代码分离 是后端工程的基本素养:代码管「怎么做」,配置管「用什么参数做」。
人话:application.yml 就是应用的「控制面板」。本站后端的数据库地址、Redis 密码、JWT 密钥全在这里管理,绝没有写死在代码里。这一课学的每个细节,上生产第一天就会用到。
先建立图像
application.yml ← 所有环境共用的配置(应用名、通用行为)
application-dev.yml ← 开发环境:H2 内存库、SQL 打印、日志 DEBUG
application-prod.yml ← 生产环境:MySQL、日志 INFO、敏感信息用环境变量
↑
启动时通过 spring.profiles.active 指定激活哪个(可同时激活多个,后者覆盖前者)
优先级(高 → 低,记住前四层够用):
命令行参数 > 环境变量 > application-{profile}.yml > application.yml
规则一句话:越「靠近启动动作」的配置越优先,Profile 专属配置覆盖通用配置。
跟着做
步骤 1:写一份规范的 application.yml
覆盖 src/main/resources/application.yml:
spring:
application:
name: taskflow
server:
port: 8080
# 自定义业务配置(约定以应用名开头,避免与框架键冲突)
taskflow:
welcome: "欢迎来到任务管理平台"
upload-dir: ./data/upload
white-list:
- 192.168.1.10
- 10.0.0.5
yml 两条铁律:缩进用空格不用 Tab ;同级键对齐,层级靠缩进表达。- 开头的行是列表元素。
步骤 2:@Value 读取(零散配置用)
写个临时 Controller 验证读取:
package com.example.taskflow.controller;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
public class ConfigDemoController {
@Value("${taskflow.welcome}")
private String welcome;
@Value("${taskflow.upload-dir}")
private String uploadDir;
@GetMapping("/api/config-demo")
public String demo() {
return welcome + " | 上传目录: " + uploadDir;
}
}
启动后访问 http://localhost:8080/api/config-demo 即可看到注入结果。${taskflow.welcome:默认值} 的冒号写法还能提供兜底默认值。
步骤 3:@ConfigurationProperties 读取(成组配置用,推荐)
零散值用 @Value, 。新建 :
一组相关配置用 @ConfigurationProperties 绑成对象
config/TaskflowProperties.java
package com.example.taskflow.config;
import org.springframework.boot.context.properties.ConfigurationProperties;
import java.util.List;
@ConfigurationProperties(prefix = "taskflow")
public record TaskflowProperties(
String welcome,
String uploadDir,
List<String> whiteList
) {}
@SpringBootApplication
@ConfigurationPropertiesScan // 让 @ConfigurationProperties 类生效
public class TaskflowApplication {
public static void main(String[] args) {
SpringApplication.run(TaskflowApplication.class, args);
}
}
@RestController
public class ConfigDemoController {
private final TaskflowProperties properties;
public ConfigDemoController(TaskflowProperties properties) {
this.properties = properties;
}
@GetMapping("/api/config-props")
public List<String> whiteList() {
return properties.whiteList();
}
}
注意:yml 里的 upload-dir(中划线)自动绑定到 uploadDir(驼峰),这叫松散绑定 ,record 的构造器绑定由 Boot 自动完成,无需任何 setter。
步骤 4:建立 dev / prod 双环境 新建 application-dev.yml(开发环境):
spring:
datasource:
url: jdbc:h2:mem:taskflow;DB_CLOSE_DELAY=-1
driver-class-name: org.h2.Driver
username: sa
password: ""
logging:
level:
com.example.taskflow: DEBUG
org.springframework.jdbc: DEBUG
新建 application-prod.yml(生产环境):
spring:
datasource:
url: jdbc:mysql://${DB_HOST:localhost}:3306/taskflow
driver-class-name: com.mysql.cj.jdbc.Driver
username: ${DB_USER:taskflow}
password: ${DB_PASSWORD} # 只从环境变量读,不写默认值
hikari:
maximum-pool-size: 20
logging:
level:
com.example.taskflow: INFO
在 application.yml 里指定默认激活 dev:
spring:
profiles:
active: dev
${DB_PASSWORD} 是占位符 :运行时从环境变量取值。配合 export DB_PASSWORD=xxx(Linux)或 IDEA Run Configuration 的 Environment variables(Windows)注入。数据库密码出现在代码仓库里是安全事故级别的问题。
步骤 5:三种方式切换 Profile 方式一:改 application.yml 的 spring.profiles.active(适合本地)。
java -jar taskflow.jar --spring.profiles.active=prod
# Linux / macOS
export SPRING_PROFILES_ACTIVE=prod
java -jar taskflow.jar
Windows PowerShell 对应 $env:SPRING_PROFILES_ACTIVE="prod"。启动日志第一行附近会打印 The following 1 profile is active: "prod",部署后先看这行确认环境没切错 。
步骤 6:动手验证优先级 mvnw spring-boot:run -Dspring-boot.run.arguments=--server.port=9090
日志会显示 Tomcat started on port 9090——yml 里的 8080 被命令行覆盖了。这就是「命令行 > yml」的直观证明。生产上紧急改个配置不用重新打包,加参数重启即可(但改完要同步回配置文件,否则下次重启回退)。
讲清楚要点
@Value 与 @ConfigurationProperties 的分工 :前者适合一两个零散值;后者把成组配置绑成类型安全对象,支持校验、IDE 提示和松散绑定,团队项目默认用它。
Profile 是「配置切片」不是「代码分支」 :application-{profile}.yml 只负责差异部分,公共配置留在主文件,避免两边各维护一份全量。
敏感信息永远走环境变量或配置中心 :yml 里只出现 ${DB_PASSWORD} 占位符。真实企业里再进一步用 Nacos/Vault 这类配置中心集中管理与加密。
优先级要理解而不是死背 :命令行和环境变量是「启动时的临时输入」,当然优先于「打进 jar 里的静态文件」;profile 文件比主文件更具体,覆盖也更合理。
改配置 = 改参数 ≠ 改代码 :凡是发现自己在代码里写 if (环境 == 生产),都是配置设计错了,把它变成配置项。
你可能会懵的地方
yml 和 properties 能混用吗?
能,Spring 会同时加载同名两种格式,yml 优先。但一个项目只统一用一种,混着写迟早有人改错文件。
多模块项目 / 打包后,配置文件从哪加载?
优先级从高到低:jar 外的 config/ 目录 → jar 外根目录 → jar 内 classpath 的 config/ → jar 内 classpath 根。所以生产上经常把 application-prod.yml 放在 jar 同级的 config/ 目录做「不改包覆盖」。
同一个 Profile 激活多个时(如 dev,local)哪个赢?
后声明的赢:spring.profiles.active=dev,local 中 local 的配置覆盖 dev 的同名键。利用这一点可以做「环境基础 + 个人本地微调」的组合。
@Value 注入的时机为什么比构造器执行早/晚出问题?
@Value 是字段注入,发生在 Bean 实例化之后。若在构造器里读这个字段还是 null——要么改用 @ConfigurationProperties + 构造器注入,要么把 @Value 挪到构造器参数上。
配置改了必须重启吗?
默认是。动态刷新需要配置中心(Nacos 等)配合 @RefreshScope,属于进阶话题;本阶段建立「改配置 → 重启 → 验证」的肌肉记忆即可。
错法对照 错法 问题 正解 yml 缩进用 Tab 解析直接报错 while scanning ... found character '\t' 全部用空格,IDE 统一格式化 数据库密码明文写进 application-prod.yml 并提交 密码泄露进 git 历史 用 ${DB_PASSWORD} + 环境变量注入 每个环境复制一份全量 application.yml 改一个公共配置要改 N 处 主文件放公共,profile 文件只放差异 生产验证只看页面不查启动日志 Profile 切错连错库而不自知 启动后确认 active profile 日志行 @Value 写错 key(如 taskflow.welcom) 启动即抛 Could not resolve placeholder 保持 key 拼写一致,或加 :默认值 兜底
卡点急救
启动报 Could not resolve placeholder 'xxx' :yml 里没有这个 key 或拼写不一致。检查 yml 层级缩进,@Value 的 key 与 yml 完全一致;临时可用 ${xxx:默认值} 兜底。
yml 报 ScannerException: mapping values are not allowed here :几乎都是缩进错位或冒号后少了空格。yml 键后必须 空格冒号空格值(key: value)。
Profile 切了但配置像没生效 :先看启动日志 The following profiles are active: ... 确认激活成功;再确认没有命令行参数或环境变量把同名键又覆盖回去了(它们优先级更高)。
环境变量注入后仍拿到 null :Windows 下检查变量名大小写与作用域(用户级/系统级需重开终端生效);IDEA 里确认配置在 Run/Debug Configuration 的 Environment variables 中。
面试常问
Spring Boot 配置文件的加载优先级?
至少说出:命令行参数 > 系统环境变量 > jar 外 config/ 目录 > jar 外根目录 > jar 内 config/ > jar 内 classpath;同层内 application-{profile}.yml 覆盖 application.yml。
@Value 和 @ConfigurationProperties 怎么选?
零散单值用 @Value;一组相关配置用 @ConfigurationProperties:类型安全、松散绑定、可配合 JSR-303 校验、支持 IDE 元数据提示,利于维护。
多环境配置怎么实现?生产敏感信息怎么管?
Profile 切片(application-{profile}.yml)+ spring.profiles.active 激活;敏感信息用环境变量占位符注入,进一步用配置中心(Nacos/Apollo/Vault)集中管理与加密。
Bootstrap 配置和 Application 配置的区别?
引入 Spring Cloud 后,bootstrap.yml 先于 application.yml 加载,用于存放连接配置中心本身的地址;纯 Boot 项目没有这个概念。
自测三问
命令行参数、环境变量、application-prod.yml、application.yml 四者的优先级从高到低怎么排?
taskflow.upload-dir 能绑定到 record 组件 uploadDir 吗?这叫什么机制?
生产环境的数据库密码应该怎么注入?写出 yml 中的占位符写法。
小结一句话 配置与代码分离、Profile 按环境切片、敏感信息走环境变量——把「控制面板」管好,应用才能一套代码跑遍所有环境。
延伸