Skip to content

Config & Env ​

解决什么问题:环境差异是部署头号杀手——dev 跑得通 prod 跑不通。把配置从代码剥离 = 同一份代码跑在多个环境。

它是什么 ​

Configuration(配置) 是会随环境变化的部分——数据库 URL、API key、开关、阈值。Environment(环境) 是配置的具体取值——dev/staging/prod。

12-Factor App 原则:

  • 配置 = 环境变量,不进代码
  • 不分环境编译(一份代码 + 不同 env)
  • 配置集中在 env / application.yml / ConfigMap

SE@G Ch 21:"Configuration should be externalized, validated, and immutable per environment."

V2 视角(V2.7 B3 分解):配置 = "变化项" 从"稳定项"中分离——环境是配置的实例化。

关键属性 ​

属性值/含义
形式环境变量 / yml/json / 配置中心(Nacos/Consul)
优先级命令行 > 环境变量 > 配置文件 > 默认值
验证启动时校验必需配置(fail-fast)
分层全局 / 服务 / 实例 / 用户(feature flag)
反模式配置进 git / 配置进代码 / 不同环境不同代码
核心约束同一份代码运行多环境(12-Factor)
判错标准部署需要改代码 = 配置没分离干净

怎么用 ​

场景 1:Spring Boot 外部化配置 ​

yaml
# application.yml(默认值)
spring:
  datasource:
    url: ${DB_URL}
    username: ${DB_USER}
    password: ${DB_PASSWORD}
bash
# 环境变量注入(dev)
DB_URL=jdbc:postgresql://localhost/app DB_USER=app ./gradlew bootRun

# 生产(k8s ConfigMap)
envFrom:
  - configMapRef:
      name: app-prod

场景 2:Feature Flag(功能开关) ​

配置不仅是基础设施,还包括业务开关:

java
@ConditionalOnProperty(name = "feature.checkout-v2.enabled", havingValue = "true")
@Service
public class CheckoutV2Service implements CheckoutService {
    // 新版结账
}

关键:Feature Flag ≠ 配置文件——通常用 LaunchDarkly / Unleash 等专门系统,支持灰度、用户分桶、A/B 测试。

场景 3:配置中心(动态配置) ​

配置文件不够的场景——配置需要运行时变更:

java
@NacosValue("${order.timeout:30s}")
private Duration orderTimeout;

特性:配置中心支持配置变更通知 + 历史版本 + 灰度推送。

常见误区 ​

  1. "配置 = 配置文件"——错。配置是"变化项"的统称,包括 Feature Flag、运行时参数
  2. "配置文件进 git"——错。含密钥的配置文件绝不能进 git——用 secret 管理(Vault / k8s Secret)
  3. "环境变量不好用"——错。环境变量是 Unix 标准,比配置文件优先——配置中心只是补充
  4. "每个环境一个 yml"——错。application-dev.yml / application-prod.yml 是反模式——只有"差异点" 才需要 yml
  5. "配置改完要重启"——错。配置中心支持热更新——但要明确哪些可热更、哪些不可

关键洞察 ​

配置是"变化"——把变化从代码剥离 = 同一份代码跑多环境 = 部署的核心抽象。

控制论视角:配置 = 系统的"可调参数"(增益、阈值)——控制器要稳定运行必须能调参。 IDDD Ch 13 视角:BC 之间的连接配置(URL、topic)应该外部化——BC 自治的工程基础。 SE@G Ch 21 视角:Google 强调配置 schema 校验——启动 fail-fast 比运行时报错安全。 EDM Ch 10 视角:事件系统的 broker、schema registry URL 必须配置化——不可硬编码。

相关链接 ​

从名家方法论与工程化思路中蒸馏出自己的工程体系。