Spring Boot: 配置管理

最后更新:2026-08-26

配置管理是应用从开发到生产的桥梁——一套代码,多套配置,环境切换只需一行参数。

1. 你将学到


2. 一个运维工程师的真实故事

(1) 痛点:配置散落各处

Bob 是 OrderFlow 的运维工程师,每次部署都像"考古":数据库密码硬编码在代码里,测试环境和生产环境的配置混在一个文件中,有人改了生产数据库密码却忘了更新代码,导致系统宕机 2 小时。Charlie 追问 SLA,Bob 只能无奈地解释"配置管理混乱"。

(2) Spring Boot Profile 的解法

Spring Boot 用 Profile 机制分离多环境配置:

YAML
# application-dev.yml
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/orderflow_dev
    username: dev_user
    password: dev_pass
YAML
# application-prod.yml
spring:
  datasource:
    url: jdbc:mysql://prod-db.internal:3306/orderflow
    username: ${DB_USERNAME}
    password: ${DB_PASSWORD}

(3) 收益

Bob 用 Profile + 环境变量重构后,开发环境用 dev、生产用 prod,敏感信息不再出现在代码仓库中,部署切换只需 --spring.profiles.active=prod,配置错误导致的宕机时间降为零。


3. Profile 多环境配置

(1) Profile 文件命名规则

Spring Boot 按 application-{profile}.yml 命名约定加载 Profile 配置:

TEXT 📖 仅展示
src/main/resources/
├── application.yml            # Common config (shared)
├── application-dev.yml        # Dev profile
├── application-prod.yml       # Prod profile
└── application-test.yml       # Test profile
100%
graph TD
    A["application.yml<br/>Common Config"] --> B["application-dev.yml<br/>Dev Overrides"]
    A --> C["application-prod.yml<br/>Prod Overrides"]
    A --> D["application-test.yml<br/>Test Overrides"]
    B --> E["Merged Config<br/>Profile=dev"]
    C --> F["Merged Config<br/>Profile=prod"]
激活方式 命令 优先级
配置文件 spring.profiles.active=dev in application.yml 最低
环境变量 SPRING_PROFILES_ACTIVE=dev
命令行参数 --spring.profiles.active=dev 最高

▶ 示例: Profile 配置文件

YAML
# application.yml (shared)
spring:
  application:
    name: orderflow-service
  profiles:
    active: dev

server:
  port: 8080

输出:

TEXT 📖 仅展示
Configuration applied successfully
YAML
# application-dev.yml
spring:
  datasource:
    url: jdbc:h2:mem:orderflow_dev
    username: sa
    password:
  jpa:
    hibernate:
      ddl-auto: create-drop
    show-sql: true

logging:
  level:
    com.orderflow: DEBUG
YAML
# application-prod.yml
spring:
  datasource:
    url: jdbc:mysql://${DB_HOST:localhost}:3306/orderflow
    username: ${DB_USERNAME}
    password: ${DB_PASSWORD}
  jpa:
    hibernate:
      ddl-auto: validate
    show-sql: false

logging:
  level:
    com.orderflow: WARN

4. @Value 与 @ConfigurationProperties 对比

(1) 两种注入方式

▶ 示例: @Value 注入

JAVA
@RestController
public class OrderController {

    @Value("${orderflow.max-items-per-order:100}")
    private int maxItemsPerOrder;

    @Value("${orderflow.default-currency:USD}")
    private String defaultCurrency;

    @GetMapping("/api/config/check")
    public Map<String, Object> checkConfig() {
        return Map.of(
            "maxItemsPerOrder", maxItemsPerOrder,
            "defaultCurrency", defaultCurrency
        );
    }
}

输出:

TEXT 📖 仅展示
// 执行成功

▶ 示例: @ConfigurationProperties 类型安全绑定

JAVA
@ConfigurationProperties(prefix = "orderflow")
public record OrderFlowProperties(
    int maxItemsPerOrder,
    String defaultCurrency,
    Duration orderTimeout,
    ShippingConfig shipping
) {
    public record ShippingConfig(
        boolean freeShippingEnabled,
        BigDecimal freeShippingThreshold
    ) {}
}

// Enable in main class or config class
@EnableConfigurationProperties(OrderFlowProperties.class)

输出:

TEXT 📖 仅展示
// 执行成功
维度 @Value @ConfigurationProperties
类型安全 弱(String 为主) 强(自动类型转换)
嵌套对象 不支持 支持
集合绑定 不支持 支持 List/Map
校验 配合 @Validated
IDE 支持 无提示 有自动补全(metadata)
适用场景 少量简单值 结构化业务配置

▶ 示例: YAML 与 ConfigurationProperties 对应

YAML
orderflow:
  max-items-per-order: 50
  default-currency: USD
  order-timeout: 30m
  shipping:
    free-shipping-enabled: true
    free-shipping-threshold: 49.99

输出:

TEXT 📖 仅展示
配置文件已生效
JAVA
// Access example
@Component
public class OrderService {
    private final OrderFlowProperties props;

    public OrderService(OrderFlowProperties props) {
        this.props = props;
    }

    public boolean isFreeShipping(BigDecimal orderTotal) {
        return props.shipping().freeShippingEnabled()
            && orderTotal.compareTo(props.shipping().freeShippingThreshold()) >= 0;
    }
}

5. 配置优先级层级

(1) 优先级从高到低

100%
graph TD
    A["1. Command Line Args<br/>--server.port=9090"] --> B["2. JNDI Attributes"]
    B --> C["3. Java System Properties<br/>-Dserver.port=9090"]
    C --> D["4. OS Environment Variables<br/>SERVER_PORT=9090"]
    D --> E["5. application-{profile}.yml<br/>Profile-specific"]
    E --> F["6. application.yml<br/>Default config"]
    F --> G["7. @Default Values<br/>In code annotations"]
优先级 来源 示例
1(最高) 命令行参数 --server.port=9090
2 JNDI 属性 java:comp/env/...
3 JVM 系统属性 -Dserver.port=9090
4 OS 环境变量 SERVER_PORT=9090
5 Profile 配置文件 application-prod.yml
6 默认配置文件 application.yml
7(最低) 代码默认值 @Value("${x:default}")
💡 提示: 生产环境推荐用环境变量或命令行参数覆盖敏感配置,不要把密码写在配置文件中。


6. 嵌套配置与集合绑定

(1) List 和 Map 绑定

▶ 示例: List 和 Map 配置

YAML
orderflow:
  supported-currencies:
    - USD
    - EUR
    - GBP
  payment-gateways:
    stripe:
      api-key: ${STRIPE_API_KEY}
      webhook-secret: ${STRIPE_WEBHOOK_SECRET}
    paypal:
      client-id: ${PAYPAL_CLIENT_ID}
      secret: ${PAYPAL_SECRET}

输出:

TEXT 📖 仅展示
CI/CD 流水线配置已加载
Pipeline 运行状态: passed
Tests: 12 passed, 0 failed
JAVA
@ConfigurationProperties(prefix = "orderflow")
public record OrderFlowProperties(
    List<String> supportedCurrencies,
    Map<String, GatewayConfig> paymentGateways
) {
    public record GatewayConfig(
        String apiKey,
        String webhookSecret,
        String clientId,
        String secret
    ) {}
}

7. 综合示例:OrderFlow 完整配置体系

JAVA
// OrderFlowProperties.java
package com.orderflow.config;

import org.springframework.boot.context.properties.ConfigurationProperties;
import java.math.BigDecimal;
import java.time.Duration;
import java.util.List;
import java.util.Map;

@ConfigurationProperties(prefix = "orderflow")
public record OrderFlowProperties(
    int maxItemsPerOrder,
    String defaultCurrency,
    Duration orderTimeout,
    ShippingConfig shipping,
    List<String> supportedCurrencies,
    Map<String, GatewayConfig> paymentGateways
) {
    public record ShippingConfig(
        boolean freeShippingEnabled,
        BigDecimal freeShippingThreshold
    ) {}

    public record GatewayConfig(
        String apiKey,
        String webhookSecret,
        String clientId,
        String secret
    ) {}
}

// AppConfig.java
package com.orderflow.config;

import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Configuration;

@Configuration
@EnableConfigurationProperties(OrderFlowProperties.class)
public class AppConfig {}
YAML
# application.yml
spring:
  application:
    name: orderflow-service
  profiles:
    active: dev

orderflow:
  max-items-per-order: 50
  default-currency: USD
  order-timeout: 30m
  supported-currencies:
    - USD
    - EUR
    - GBP
  shipping:
    free-shipping-enabled: true
    free-shipping-threshold: 49.99
  payment-gateways:
    stripe:
      api-key: ${STRIPE_API_KEY:dev-key}
      webhook-secret: ${STRIPE_WEBHOOK_SECRET:dev-secret}

❓ 常见问题

Q @ConfigurationProperties 和 @Value 该选哪个?
A 结构化配置用 @ConfigurationProperties(类型安全、嵌套、IDE 支持),少量简单值用 @Value。一个项目不要混用太多。
Q 如何防止敏感信息泄露到代码仓库?
A 1)配置文件中使用 ${ENV_VAR} 占位符引用环境变量;2).gitignore 排除敏感配置文件;3)生产环境用 K8s Secret 或 Vault 管理密钥。
Q Profile 配置和默认配置如何合并?
A Spring Boot 先加载默认配置,再用 Profile 配置覆盖相同属性。不同属性互补,相同属性 Profile 优先。
Q YAML 中的 List 在 Properties 中怎么写?
A orderflow.supported-currencies[0]=USDorderflow.supported-currencies[1]=EUR。List 索引从 0 开始。
Q 如何在代码中动态切换 Profile?
A 不推荐在代码中动态切换。Profile 应在启动时确定。如果需要运行时动态切换配置,使用 Spring Cloud Config 或自定义配置刷新机制。
Q record 作为 ConfigurationProperties 有什么限制?
A record 是不可变的,适合只读配置。Spring Boot 3.x 支持 record 绑定。但无法配合 @Validated 进行 JSR-380 校验(record 无无参构造器),需要用类替代。

📖 小节


📝 作业

  1. 基础题(难度⭐):为 OrderFlow 配置 dev 和 prod 两个 Profile,dev 使用 H2 内存数据库,prod 使用 MySQL,通过命令行参数切换。

  2. 进阶题(难度⭐⭐):使用 @ConfigurationProperties 创建 PaymentGatewayProperties,包含 Stripe 和 PayPal 的 API 密钥配置,通过环境变量注入密钥值。

  3. 挑战题(难度⭐⭐⭐):实现自定义 PropertySource,从远程配置中心(可用 mock HTTP 接口)加载配置,思考 Spring Boot Environment 抽象的设计意图。

Web-Tutorial.com

Web-Tutorial 技术团队

由多位开发者共同维护的编程教程平台。每篇教程由对应领域的开发者编写和审核,确保内容准确可靠。如发现任何问题,欢迎向我们反馈。

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏