bigywater.tech
Spring · 69

外部化配置的来源与优先级:命令行、环境变量、配置文件

同一个配置写在好几个地方到底谁生效?环境变量和 -D 谁大?profile 专属配置一定更高吗?my.appName 能读到 my.app-name 吗?这篇把同一个属性放进 12 个来源,逐个拿掉最高的来源,在 Spring Boot 4.0.8 上实测。

12
参与比较的来源个数
系统属性 > 环境变量
JVM -D 系统属性高于操作系统环境变量
jar 外 > jar 内 profile
jar 内 application-dev.properties 输给 jar 外的 ./config/application.properties

优先级

实测 · 本机执行输出
  剩下 12 个来源,最高的是「命令行参数 --app.name=cmdline」→ cmdline ←|← commandLineArgs
  剩下 11 个来源,最高的是「环境变量 SPRING_APPLICATION_JSON」→ spring-application-json ←|← spring.application.json
  剩下 10 个来源,最高的是「JVM 系统属性 -Dapp.name=sysprop」→ sysprop ←|← systemProperties
  剩下  9 个来源,最高的是「操作系统环境变量 APP_NAME」→ os-env ←|← systemEnvironment
  剩下  8 个来源,最高的是「jar 外:./config/application-dev.properties(profile=dev)」→ cwd-config-dev ←|← file:[config/application-dev.properties]
  剩下  7 个来源,最高的是「jar 内:classpath:application-dev.properties(profile=dev)」→ cwd-config ←|← file:[config/application.properties]
  剩下  6 个来源,最高的是「jar 外:./config/application.properties」→ cwd-config ←|← file:[config/application.properties]
  剩下  5 个来源,最高的是「jar 外:./application.properties」→ cwd ←|← file:[application.properties]
  剩下  4 个来源,最高的是「jar 内:classpath:/config/application.properties」→ classpath-config ←|← classpath:[config/application.properties]
  剩下  3 个来源,最高的是「jar 内:classpath:/application.properties」→ classpath ←|← classpath:[application.properties]
  剩下  2 个来源,最高的是「@PropertySource("classpath:/extra.properties")」→ property-source ←|← class path resource [extra.properties]
  剩下  1 个来源,最高的是「SpringApplication.setDefaultProperties」→ default-properties ←|← defaultProperties

从命令行到默认属性共 12 层,实测顺序见正文。

key 写法

实测 · 本机执行输出
  配置:application.properties 里 my.app-name=from-properties;环境变量 MY_OTHER_NAME=from-env、OTHERNAME=env2
  getProperty("my.app-name"   ) = from-properties
  getProperty("my.appName"    ) = null
  getProperty("my.app_name"   ) = null
  getProperty("MY.APP-NAME"   ) = null
  getProperty("my.camelcase"  ) = camel
  getProperty("my.camel-case" ) = camel
  getProperty("my.snake-case" ) = snake
  getProperty("my.snake_case" ) = snake
  getProperty("my.other-name" ) = from-env
  getProperty("my.otherName"  ) = null
  getProperty("my.other_name" ) = from-env
  getProperty("MY_OTHER_NAME" ) = from-env
  getProperty("my.upper"      ) = x

getProperty 要对上规范形式,环境变量按下划线映射。

占位符

实测 · 本机执行输出
  getProperty("base"          ) = B
  getProperty("full"          ) = B-suffix
  getProperty("ref"           ) = fallback
  getProperty("nested"        ) = B-suffix!
  getProperty("missing"       ) = null
  getProperty("r"             ) = 133
  getProperty("u"             ) = 897aacd1-bd13-4101-994b-accc0336f300
  getProperty("esc"           ) = a${base}

支持嵌套、默认值、random 和转义。

分步演示

外部化配置
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / OpenJDK 21.0.12(Homebrew) / Spring Boot 4.0.8(Spring Framework 7.0.9、Tomcat 11.0.24) / Spring Cloud 2025.1.3;用 javac 编译、java 直接运行,依赖由 Maven 从 Maven Central 解析;数字每次运行会有小幅抖动。用 Spring Boot 4.0.8(spring-boot-starter,非 Web 模式)的单个程序,每个来源一个独立 JVM 运行;工作目录是临时目录,jar 内的文件放在 classpath 目录里(不是真正的 jar);来源名取自 Environment 的 PropertySources 中第一个包含该属性的那个
    • 没有验证:真正的可执行 jar 里的 BOOT-INF/classes;spring.config.name / spring.config.location 的效果(见第 70 篇);@TestPropertySource、@SpringBootTest(properties=...) 等测试里的来源;Servlet 上下文 init 参数、JNDI 来源;Kubernetes ConfigMap 挂载成文件或环境变量时的行为;@ConfigurationProperties 的宽松绑定规则(见第 71 篇)
    京ICP备2026067502号-1京公网安备11010502063487号