乐途乐途
主页
  • 计算机基础

    • TCP/IP
    • Linux
    • HTTP
  • 数据库

    • SQL
    • MySQL 5.7
  • 编程语言

    • C
    • C++
    • Java SE
    • Python2
    • Python3
  • 数据格式

    • JSON
    • XML
  • 认证与安全

    • JWT
  • 工具

    • Markdown
  • Git

    • GitFlow
  • Quartz

    • Quartz
  • Java

    • Maven 入门
    • Maven 进阶
    • MyBatis
    • Spring
    • Spring MVC
  • Java

    • Spring Boot
    • Spring Cloud
    • Spring Cloud Alibaba
    • Spring Security
    • Spring AI
    • Spring Batch
    • Kafka
    • Java 设计模式
  • 缓存

    • Redis
  • 搜索引擎

    • Elasticsearch
  • 分布式协调

    • ZooKeeper
联系
阿里云
主页
  • 计算机基础

    • TCP/IP
    • Linux
    • HTTP
  • 数据库

    • SQL
    • MySQL 5.7
  • 编程语言

    • C
    • C++
    • Java SE
    • Python2
    • Python3
  • 数据格式

    • JSON
    • XML
  • 认证与安全

    • JWT
  • 工具

    • Markdown
  • Git

    • GitFlow
  • Quartz

    • Quartz
  • Java

    • Maven 入门
    • Maven 进阶
    • MyBatis
    • Spring
    • Spring MVC
  • Java

    • Spring Boot
    • Spring Cloud
    • Spring Cloud Alibaba
    • Spring Security
    • Spring AI
    • Spring Batch
    • Kafka
    • Java 设计模式
  • 缓存

    • Redis
  • 搜索引擎

    • Elasticsearch
  • 分布式协调

    • ZooKeeper
联系
阿里云
  • 学习路径
  • 第1章 Spring Boot 概述

    • 章节导读:Spring Boot概述与核心理念
    • Spring Boot是什么
    • Spring Boot与Spring Framework的关系
    • 约定优于配置
  • 第2章 快速入门与第一个应用

    • 章节导读:快速入门与第一个应用
    • SpringApplication
    • 第一个Spring Boot应用
  • 第3章 起步依赖与版本管理

    • 章节导读:起步依赖与版本管理
    • 起步依赖
    • BOM版本管理
  • 第4章 自动配置原理

    • 章节导读:自动配置原理
    • 自动配置原理
    • AutoConfigurationImportSelector
    • 自动配置报告
  • 第5章 核心注解

    • 章节导读:核心注解
    • @SpringBootApplication
    • @EnableAutoConfiguration
    • @ConditionalOnClass
    • @ConditionalOnMissingBean
    • @ConditionalOnBean
    • @ConditionalOnProperty
  • 第6章 外部化配置与属性绑定

    • 章节导读:外部化配置与属性绑定
    • 外部化配置
    • @ConfigurationProperties
    • @Value
    • 配置属性优先级
  • 第7章 Profile 与环境切换

    • 章节导读:Profile与环境切换
    • @Profile
    • 多环境配置文件
  • 第8章 内嵌服务器与部署

    • 章节导读:内嵌服务器与部署
    • 内嵌服务器
    • Fat Jar
  • 第9章 Actuator 与监控

    • 章节导读:Actuator与监控
    • Actuator Health
    • Actuator Info
    • Actuator Metrics
    • 自定义Endpoint
    • 自定义HealthIndicator
  • 第10章 开发工具与最佳实践

    • 章节导读:开发工具与最佳实践
    • Banner自定义
    • 热部署

多环境配置文件

一句话定位:多环境配置文件是 Spring Boot 的按环境拆分配置机制,通过 application-{profile}.yml 的命名约定将公共配置与环境特有配置分离,配合多文档 YAML 语法在单文件内实现多环境切换。


定义与作用

多环境配置文件 是 Spring Boot 对 Profile 机制的配置文件层实现。它允许开发者将公共配置放在 application.yml 中,将环境特有配置放在 application-dev.yml、application-test.yml、application-prod.yml 中。当激活某个 Profile 时,Spring Boot 自动加载对应的配置文件,并将其中的属性覆盖到公共配置之上。

命名约定

文件名说明激活条件
application.yml公共配置,所有环境共享始终加载
application-dev.yml开发环境特有配置spring.profiles.active=dev
application-test.yml测试环境特有配置spring.profiles.active=test
application-prod.yml生产环境特有配置spring.profiles.active=prod
application-{profile}.yml任意自定义 Profile对应 Profile 激活时加载

对比传统 SSM 的繁琐过程

维度传统 SSMSpring Boot 多环境配置文件
文件组织所有环境配置混杂在 applicationContext.xml 中每个环境独立文件,清晰分离
环境切换手动注释/取消注释 XML 中的配置块一条命令自动加载对应文件
版本控制生产密码容易误提交到仓库敏感配置放在外部文件,不提交
可读性一个文件几百行,维护困难每个文件职责单一,一目了然

适用位置与常用属性

配置文件加载位置(按优先级)

位置优先级说明
./config/application-{profile}.yml高JAR 外部 config 子目录,运维最常用
./application-{profile}.yml中高JAR 同级目录
classpath:config/application-{profile}.yml中打包在 JAR 内的 config 目录
classpath:application-{profile}.yml低打包在 JAR 内的根目录(本教程默认位置)

多文档 YAML 语法(Spring Boot 2.4+)

除了拆分成多个文件,Spring Boot 还支持在单个 application.yml 文件内用 --- 分隔多个文档,每个文档独立配置:

# application.yml 多文档结构
spring:
  config:
    activate:
      on-profile: default

server:
  port: 8080

---

spring:
  config:
    activate:
      on-profile: dev

server:
  port: 8080

debug: true

---

spring:
  config:
    activate:
      on-profile: prod

server:
  port: 80

debug: false
属性说明示例
spring.config.activate.on-profile指定该文档的生效 Profiledev
---YAML 多文档分隔符分隔不同环境配置块
spring.profiles.active激活的 Profile 列表dev,localcache
spring.profiles.include无条件额外包含的 Profilecommon

核心原理

多环境配置文件加载与合并流程

图解释:Spring Boot 启动时先加载 application.yml(公共配置),然后根据激活的 Profile 加载对应的 application-{profile}.yml。两文件的配置合并到 Environment 中,Profile 特有配置的同名属性覆盖公共配置,不同名属性共存。

文件层级与优先级关系

图解释:文件优先级遵循"外部 > 内部、Profile 文件 > 非 Profile 文件、config 目录 > 当前目录"的规则。运维在生产环境部署时,通常将 application-prod.yml 放在 ./config/ 目录下,确保其优先级最高且不会被误打包进 JAR。


完整示例

场景说明

飞翔科技的学生成绩管理系统需要部署到三种环境:

  • dev:本地开发,H2 数据库,端口 8080,开启 SQL 日志
  • test:QA 测试,MySQL 测试库,端口 8081,关闭 SQL 日志
  • prod:线上生产,MySQL 生产库,端口 80,关闭 SQL 日志,开启 SSL

后端开发小崔需要为每种环境准备独立的配置文件,同时确保公共配置(如应用名称、版本)不需要重复写三份。

操作前:所有配置塞在一个文件,混乱不堪

# 操作前:一个 application.yml 塞了所有环境的配置,靠注释切换
server:
  port: 8080  # dev:8080, test:8081, prod:80

spring:
  datasource:
    # 开发用 H2
    url: jdbc:h2:mem:student_db
    driver-class-name: org.h2.Driver
    # 测试用 MySQL(需要手动取消注释)
    # url: jdbc:mysql://test-db:3306/student_db
    # driver-class-name: com.mysql.cj.jdbc.Driver
    # username: test_user
    # password: test_pass

feixiang:
  student:
    system-name: "飞翔科技学生成绩管理系统"
    # debug-mode: true  # dev 开启
    debug-mode: false   # 其他环境关闭(需要手动改)

痛点:

  • 小崔在 dev 时把 debug-mode 改成 true,提交到仓库后,测试同事启动时也是 true
  • 生产数据库密码写在公共配置文件中,提交到 Git 仓库有安全隐患
  • 每次切换环境都要手动改 YAML 并重新编译,极易出错

使用多环境配置文件的完整代码

步骤1:公共配置 application.yml

# src/main/resources/application.yml(公共配置,所有环境共享)
server:
  port: 8080

spring:
  application:
    name: student-system
  profiles:
    active: dev  # 默认激活 dev,方便本地开发

feixiang:
  student:
    system-name: "飞翔科技学生成绩管理系统"
    version: "2.7.18"
    max-upload-size: 10MB

步骤2:开发环境 application-dev.yml

# src/main/resources/application-dev.yml(dev 环境特有)
spring:
  datasource:
    url: jdbc:h2:mem:student_db;DB_CLOSE_DELAY=-1;MODE=MySQL
    driver-class-name: org.h2.Driver
    username: sa
    password:
  jpa:
    show-sql: true  # 开发环境打印 SQL,方便调试
    hibernate:
      ddl-auto: create-drop  # 每次启动重建表

feixiang:
  student:
    debug-mode: true
    log-level: DEBUG
    allowed-origins: "*"

步骤3:测试环境 application-test.yml

# src/main/resources/application-test.yml(test 环境特有)
spring:
  datasource:
    url: jdbc:mysql://test-db:3306/student_db?useSSL=false&serverTimezone=Asia/Shanghai
    driver-class-name: com.mysql.cj.jdbc.Driver
    username: test_user
    password: test_pass
  jpa:
    show-sql: false
    hibernate:
      ddl-auto: validate  # 只验证表结构,不修改

feixiang:
  student:
    debug-mode: false
    log-level: WARN
    allowed-origins: "http://test.feixiang.com"

步骤4:生产环境 application-prod.yml

# src/main/resources/application-prod.yml(prod 环境特有,打包时不包含敏感信息)
server:
  port: 80

spring:
  datasource:
    url: jdbc:mysql://prod-db:3306/student_db?useSSL=true&serverTimezone=Asia/Shanghai
    driver-class-name: com.mysql.cj.jdbc.Driver
    username: ${DB_USERNAME}  # 从环境变量读取,不硬编码
    password: ${DB_PASSWORD}  # 从环境变量读取,不硬编码
  jpa:
    show-sql: false
    hibernate:
      ddl-auto: none  # 生产环境禁止自动修改表结构

feixiang:
  student:
    debug-mode: false
    log-level: ERROR
    allowed-origins: "https://student.feixiang.com"

生产安全提示:application-prod.yml 中的数据库密码使用 ${DB_USERNAME} 占位符,实际值通过服务器环境变量传入。该文件可以放入代码仓库(不含真实密码),真实密码由运维在部署时配置。

步骤5:不同环境启动验证

package com.feixiang.student.service;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

@Service
public class EnvironmentService {
    
    @Value("${server.port}")
    private int port;
    
    @Value("${spring.datasource.url}")
    private String dbUrl;
    
    @Value("${feixiang.student.debug-mode}")
    private boolean debugMode;
    
    @Value("${feixiang.student.log-level}")
    private String logLevel;
    
    public void printEnvironment() {
        System.out.println("=== 当前环境配置 ===");
        System.out.println("端口: " + port);
        System.out.println("数据库: " + dbUrl);
        System.out.println("调试模式: " + debugMode);
        System.out.println("日志级别: " + logLevel);
    }
}

操作后运行结果及分析

dev 环境启动(默认,spring.profiles.active: dev):

=== 当前环境配置 ===
端口: 8080
数据库: jdbc:h2:mem:student_db;DB_CLOSE_DELAY=-1;MODE=MySQL
调试模式: true
日志级别: DEBUG

test 环境启动(--spring.profiles.active=test):

=== 当前环境配置 ===
端口: 8080                          ← 来自 application.yml 公共配置
数据库: jdbc:mysql://test-db:3306/student_db?useSSL=false&serverTimezone=Asia/Shanghai
调试模式: false
日志级别: WARN

prod 环境启动(--spring.profiles.active=prod):

=== 当前环境配置 ===
端口: 80                            ← 被 application-prod.yml 覆盖
数据库: jdbc:mysql://prod-db:3306/student_db?useSSL=true&serverTimezone=Asia/Shanghai
调试模式: false
日志级别: ERROR

分析:

  1. 公共配置复用:system-name、version 等公共属性只在 application.yml 中写一次,所有环境共享
  2. 环境特有覆盖:application-dev.yml 中的 debug-mode: true 只在 dev 环境生效,test/prod 使用各自配置
  3. 端口差异化:application-prod.yml 将端口覆盖为 80,dev/test 使用公共默认值 8080
  4. 数据库隔离:三种环境使用完全不同的数据库连接,彻底避免"开发连到生产库"的事故
  5. 安全密码管理:生产数据库密码通过环境变量 ${DB_PASSWORD} 传入,不写入代码仓库

易错场景与面试考点

易错场景一:多文档 YAML 中 spring.profiles 语法过时

小崔在 Spring Boot 2.7 中使用旧版语法写多文档 YAML:

# 错误示范:Spring Boot 2.4+ 已废弃的语法
spring:
  profiles: dev  # ← 旧语法,不生效!

server:
  port: 8080

---

spring:
  profiles: prod  # ← 旧语法,不生效!

server:
  port: 80

后果:Spring Boot 2.4 开始将 spring.profiles 改为 spring.config.activate.on-profile。使用旧语法时,Profile 条件判断失效,所有文档的配置都被加载并合并,导致端口等属性被错误覆盖。

正确做法:Spring Boot 2.4+ 必须使用新语法:

spring:
  config:
    activate:
      on-profile: dev

server:
  port: 8080

---

spring:
  config:
    activate:
      on-profile: prod

server:
  port: 80

易错场景二:Profile 文件放错位置导致未加载

小崔把 application-prod.yml 放在 src/main/resources/config/ 目录下:

src/main/resources/
  ├── application.yml
  └── config/
      └── application-prod.yml   # ← 小崔放这里

然后在 JAR 外部又放了一个 application-prod.yml:

/opt/apps/
  ├── student-system.jar
  └── application-prod.yml       # ← 运维放这里

后果:Spring Boot 的加载顺序是 ./config/ > ./ > classpath:config/ > classpath/。如果运维在 ./config/ 也放了一个文件,classpath:config/application-prod.yml 会被完全覆盖。小崔以为自己的文件生效了,实际运行的是运维的文件。

正确做法:在团队协作中约定统一的文件放置规范。开发阶段统一放在 src/main/resources/(classpath),运维覆盖阶段统一放在 ./config/(JAR 外部)。避免多位置文件互相覆盖导致困惑。

面试考点

Q:application.yml 和 application-dev.yml 的加载顺序是什么?同名属性谁覆盖谁?

先加载 application.yml(公共配置),再加载 application-dev.yml(Profile 特有配置)。application-dev.yml 中的同名属性覆盖 application.yml 中的值。不同名属性共存,合并为最终配置。

Q:多文档 YAML 中 --- 的作用是什么?

--- 是 YAML 标准的多文档分隔符。在 Spring Boot 的 application.yml 中,它用于将单个文件拆分为多个独立的配置文档,每个文档可以有自己的 spring.config.activate.on-profile 条件。适合配置项较少的场景,避免创建过多文件。

Q:生产环境的数据库密码如何安全管理?

三种方式:1. application-prod.yml 中使用 ${DB_PASSWORD} 占位符,实际值通过环境变量传入;2. 将 application-prod.yml 放在 JAR 外部的 ./config/ 目录,不打包进 JAR;3. 使用配置中心(Spring Cloud Config)集中管理敏感配置。本教程推荐前两种结合使用。

Q:spring.profiles.active 和 spring.profiles.include 有什么区别?

spring.profiles.active 是显式激活的 Profile 列表,决定加载哪些 application-{profile}.yml;spring.profiles.include 是无条件包含的额外 Profile,无论 active 是什么都会加载。例如 active: prod + include: metrics 会同时加载 application-prod.yml 和 application-metrics.yml。

Q:Spring Boot 的 Profile 配置文件可以放在哪些位置?

四个位置,按优先级从高到低:1. ./config/(JAR 外部 config 子目录);2. ./(JAR 同级目录);3. classpath:config/(JAR 内部的 config 目录);4. classpath:/(JAR 内部的根目录)。运维常用 ./config/ 放置生产配置,因为优先级最高且不随 JAR 包重新打包。

上一页
@Profile