一、为什么需要多环境配置

实际项目中,同一套代码至少要在三种环境中运行:

环境 数据库地址 日志级别 调试功能 第三方服务
开发(dev) localhost:3306 DEBUG 启用 沙箱环境
测试(test) 192.168.1.100:3306 INFO 关闭 沙箱环境
生产(prod) rm-xxx.mysql.rds.aliyuncs.com WARN 关闭 正式环境

如果把这些差异硬编码在 application.yml 中,每次部署都要手动改配置,极易出错。Spring Boot 的 Profile 机制就是解决这个问题的——同一套代码,不同环境加载不同配置

二、Profile 的本质

Profile 不是"切换配置文件"这么简单。它的本质是条件化的 PropertySource 加载

Spring Boot 启动时,会构建一个 Environment 对象,内部维护一个 PropertySource 列表。每个 Profile 对应一个独立的 PropertySource(通常是一个 YAML 文件)。激活某个 Profile,就是把这个 Profile 对应的 PropertySource 插入到列表中的特定位置,使其参与配置合并。

最终应用看到的配置,是所有 PropertySource 按优先级合并后的结果

三、Profile 配置文件的命名与加载规则

3.1 命名规范

application.yml              # 主配置(所有环境共享的默认配置)
application-dev.yml          # dev 环境专属配置
application-test.yml         # test 环境专属配置
application-prod.yml         # prod 环境专属配置
application-local.yml        # 自定义 profile(完全合法)

application.yml # 主配置(所有环境共享的默认配置) application-dev.yml # dev 环境专属配置 application-test.yml # test 环境专属配置 application-prod.yml # prod 环境专属配置 application-local.yml # 自定义 profile(完全合法)

命名规则是固定的:application-{profile}.yml{profile} 可以是任意字符串。

3.2 加载位置

Profile 配置文件和主配置文件共享相同的搜索路径:

1. ./config/application-{profile}.yml          (jar 包外部 config 目录)
2. ./application-{profile}.yml                 (jar 包外部当前目录)
3. classpath:/config/application-{profile}.yml  (jar 包内部 config 目录)
4. classpath:/application-{profile}.yml        (jar 包内部根目录)

优先级与主配置一致:外部 > 内部,config 目录 > 当前目录

3.3 多个 profile 同时激活时的加载顺序

当 spring.profiles.active=dev,test 时,Spring Boot 按声明顺序加载:

application.yml
application-dev.yml    ← 先加载
application-test.yml   ← 后加载

后加载的 profile 配置会覆盖先加载的同名配置。也就是说,test 的优先级高于 dev

四、Profile 激活的六种方式

方式 1:配置文件内声明(最常用)

# application.yml
spring:
  profiles:
    active: dev

这是开发阶段最常用的方式,直接在主配置中指定默认激活的 profile。

方式 2:命令行参数(优先级最高,生产环境最常用)

java -jar app.jar --spring.profiles.active=prod

命令行参数的优先级高于配置文件。这意味着即使 application.yml 中写了 active: dev,命令行传入 prod 后,最终激活的是 prod

为什么生产环境推荐命令行方式? 因为 jar 包内部的配置文件不应该包含环境信息。打包一次,到处运行,环境通过启动参数注入,这是容器化部署的标准做法。

方式 3:JVM 系统属性

java -Dspring.profiles.active=prod -jar app.jar

-D 参数设置的是 System.getProperties() 中的属性,优先级高于配置文件但低于命令行参数。

方式 4:环境变量

export SPRING_PROFILES_ACTIVE=prod
java -jar app.jar

环境变量名映射规则:spring.profiles.active → SPRING_PROFILES_ACTIVE(点转下划线,全大写)。这是云原生部署(Kubernetes、Docker)中最常见的方式,因为容器编排平台通常通过环境变量注入配置。

方式 5:SpringApplication 编程式设置

SpringApplication app = new SpringApplication(MyApp.class);
app.setAdditionalProfiles("dev", "local");
app.run(args);

这种方式在单元测试或启动器封装中偶尔使用,可以硬编码默认 profile。

方式 6:Maven 构建时指定

Maven:

<plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
    <configuration>
        <profiles>
            <profile>dev</profile>
        </profiles>
    </configuration>
</plugin>

六种方式的优先级(由高到低)

1. SpringApplication.setAdditionalProfiles()
2. 命令行参数(--spring.profiles.active)
3. JVM 系统属性(-Dspring.profiles.active)
4. 环境变量(SPRING_PROFILES_ACTIVE)
5. jar 外部的 profile-specific 配置文件
6. jar 内部的 profile-specific 配置文件
7. application.yml 中的 spring.profiles.active 声明

核心原则:越靠近运行时的配置源,优先级越高。命令行 > 环境变量 > 配置文件。

五、配置合并与覆盖的底层规则

假设有以下三个文件:

application.yml

server:
  port: 8080

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver

app:
  name: myapp
  features:
    - cache
    - metrics
  debug: true

application-dev.yml

server:
  port: 8081

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/dev_db
    username: root

app:
  debug: false

激活 dev 后的最终配置:

server:
  port: 8081                          ← dev 覆盖主配置

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver  ← 来自主配置
    url: jdbc:mysql://localhost:3306/dev_db     ← 来自 dev
    username: root                               ← 来自 dev

app:
  name: myapp                         ← 来自主配置(dev 未定义)
  features:                           ← 来自主配置(dev 未定义)
    - cache
    - metrics
  debug: false                        ← dev 覆盖主配置

合并规则:

  1. key 级别覆盖:同名 key,profile 的值覆盖主配置的值
  2. 不存在的 key 保留:profile 没定义的 key,主配置的值仍然有效
  3. 不是文件级别替换:主配置不会被整体丢弃

六、代码层面的 Profile 控制:@Profile

Profile 不仅能控制配置文件的加载,还能控制 Bean 的注册。

6.1 只在特定环境注册 Bean

@Component
@Profile("dev")
public class DevDatabaseSeeder {
    @PostConstruct
    public void seed() {
        // 开发环境自动插入测试数据
    }
}

@Profile("dev") 表示只有当 dev profile 激活时,这个 Bean 才会被注册到 Spring 容器中。在其他环境下,这个 Bean 不存在。

七、Profile 分组(Spring Boot 2.4+)

Spring Boot 2.4 引入了 Profile Group,可以把多个 profile 组合成一个逻辑单元。

7.1 基本用法

# application.yml
spring:
  profiles:
    group:
      production: prod,proddb,prodcache,prodlog
    active: production

执行 production 会同时激活 prodproddbprodcacheprodlog 四个 profile,按声明顺序加载。

八、工程实战技巧

本地开发覆盖特定配置

开发时,你可能想只覆盖某个配置项,又不想维护一个完整的 application-local.yml。可以用 spring.profiles.include

# application.yml
spring:
  profiles:
    active: dev
    include: local-override

然后在 application-local-override.yml 中只写需要覆盖的项:

# application-local-override.yml
app:
  feature-flag:
    new-ui: true

敏感信息外部化

生产环境的密码、密钥不应放在代码仓库中。最佳实践:

application-prod.yml(提交到仓库,不含敏感信息):

spring:
  datasource:
    url: jdbc:mysql://prod-db:3306/mydb
    username: ${DB_USERNAME}
    password: ${DB_PASSWORD}

app:
  aliyun:
    access-key-id: ${ALIYUN_ACCESS_KEY_ID}
    access-key-secret: ${ALIYUN_ACCESS_KEY_SECRET}

启动时通过环境变量注入:

export DB_USERNAME=app_user
export DB_PASSWORD=secret123
export ALIYUN_ACCESS_KEY_ID=LTAIxxx
export ALIYUN_ACCESS_KEY_SECRET=xxxx
java -jar app.jar --spring.profiles.active=prod

日志级别按环境隔离

# application.yml(所有环境)
logging:
  level:
    root: INFO

---
# dev 环境
spring:
  config:
    activate:
      on-profile: dev
logging:
  level:
    root: DEBUG
    com.example: TRACE

---
# prod 环境
spring:
  config:
    activate:
      on-profile: prod
logging:
  level:
    root: WARN
    com.example: INFO

默认 profile 兜底

spring:
  profiles:
    active: ${SPRING_PROFILES_ACTIVE:dev}

如果环境变量 SPRING_PROFILES_ACTIVE 未设置,默认激活 dev。避免没有任何 profile 激活时的配置缺失。

测试类指定 Profile

@SpringBootTest
@ActiveProfiles("test")
class OrderServiceTest {
    // 测试环境使用嵌入式数据库和模拟服务
}

@ActiveProfiles 是测试专用的 profile 激活注解,优先级高于 application.yml 中的配置。

九、总结

Profile 是 Spring Boot 多环境配置管理的核心机制,理解以下要点即可驾驭:

要点 核心内容
本质 条件化的 PropertySource 加载与合并
命名 application-{profile}.yml
激活 命令行 > 环境变量 > 配置文件,生产环境推荐命令行或环境变量
合并 key 级别覆盖,不是文件替换;列表整体覆盖不合并
代码控制 @Profile 控制 Bean 注册,@ActiveProfiles 控制测试环境
分组 spring.profiles.group 实现多 profile 组合
单文件 --- + spring.config.activate.on-profile
最佳实践 敏感信息外部化、默认 profile 兜底、日志按环境隔离、Docker/K8s 运行时注入
Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐