CodeRoadMap
首页路线题库资源库文章社区
CodeRoadMap

程序员的学习成长路线图。内容免费开放,登录后可同步路线图与课时进度。

由 程序员柏风 独立维护 · 关于作者

学习

  • 路线图
  • 课程
  • 面试题
  • 文章
  • 我

更多

  • 资源
  • 社区
  • 关于作者
  • 内容说明

© 2026 CodeRoadMap

津ICP备2026012044号-1·津公网安备12011002026155号·coderoadmap@126.com
Spring Boot 实战入门/课时/配置与 Profile
RawBlame
课时目录16 节

Spring Boot 实战入门

  1. 01Spring Boot 是什么
  2. 02Starter 与自动配置
  3. 03配置与 Profile
  4. 04IoC 与依赖注入
  5. 05Bean 作用域与生命周期
  6. 06Spring AOP 入门
  7. 07Spring MVC 与 REST
  8. 08参数校验与异常处理
  9. 09JDBC 与 MyBatis
  10. 10Spring Data JPA 入门
  11. 11事务管理
  12. 12Spring Security 基础
  13. 13JWT 与 API 鉴权
  14. 14单元测试与 MockMvc
  15. 15Actuator 与健康检查
  16. 16综合练习与进阶路线

配置与 Profile

application.yml、环境变量、dev/prod 切换。

30 分钟

配置与 Profile

这一课你将能做到

  1. 用 yml 组织项目配置,并用 @Value 和 @ConfigurationProperties 两种方式注入到代码
  2. 建立 dev / prod 多环境配置,用三种方式(yml、命令行、环境变量)切换 Profile
  3. 说清 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);
    }
}

在任意 Bean 中注入使用:

@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:动手验证优先级

保持 dev 激活,用命令行覆盖端口启动:

mvnw spring-boot:run -Dspring-boot.run.arguments=--server.port=9090

日志会显示 Tomcat started on port 9090——yml 里的 8080 被命令行覆盖了。这就是「命令行 > yml」的直观证明。生产上紧急改个配置不用重新打包,加参数重启即可(但改完要同步回配置文件,否则下次重启回退)。

讲清楚要点

  1. @Value 与 @ConfigurationProperties 的分工:前者适合一两个零散值;后者把成组配置绑成类型安全对象,支持校验、IDE 提示和松散绑定,团队项目默认用它。
  2. Profile 是「配置切片」不是「代码分支」:application-{profile}.yml 只负责差异部分,公共配置留在主文件,避免两边各维护一份全量。
  3. 敏感信息永远走环境变量或配置中心:yml 里只出现 ${DB_PASSWORD} 占位符。真实企业里再进一步用 Nacos/Vault 这类配置中心集中管理与加密。
  4. 优先级要理解而不是死背:命令行和环境变量是「启动时的临时输入」,当然优先于「打进 jar 里的静态文件」;profile 文件比主文件更具体,覆盖也更合理。
  5. 改配置 = 改参数 ≠ 改代码:凡是发现自己在代码里写 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 拼写一致,或加 :默认值 兜底

卡点急救

  1. 启动报 Could not resolve placeholder 'xxx':yml 里没有这个 key 或拼写不一致。检查 yml 层级缩进,@Value 的 key 与 yml 完全一致;临时可用 ${xxx:默认值} 兜底。
  2. yml 报 ScannerException: mapping values are not allowed here:几乎都是缩进错位或冒号后少了空格。yml 键后必须 空格冒号空格值(key: value)。
  3. Profile 切了但配置像没生效:先看启动日志 The following profiles are active: ... 确认激活成功;再确认没有命令行参数或环境变量把同名键又覆盖回去了(它们优先级更高)。
  4. 环境变量注入后仍拿到 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 项目没有这个概念。

自测三问

  1. 命令行参数、环境变量、application-prod.yml、application.yml 四者的优先级从高到低怎么排?
  2. taskflow.upload-dir 能绑定到 record 组件 uploadDir 吗?这叫什么机制?
  3. 生产环境的数据库密码应该怎么注入?写出 yml 中的占位符写法。

小结一句话

配置与代码分离、Profile 按环境切片、敏感信息走环境变量——把「控制面板」管好,应用才能一套代码跑遍所有环境。

延伸

  • Spring Boot 官方文档:Externalized Configuration
  • Spring Boot 官方文档:Profiles
  • 下一课:IoC 与依赖注入——把「对象自己 new」变成「容器送上门」。
加载本节练习…
← 上一课Starter 与自动配置下一课 →IoC 与依赖注入