首页 / Spring Boot 入门教程 / 外部化配置与优先级

Spring Boot 入门教程

外部化配置与优先级

本教程共 48 篇 · 第 12 篇 · 更新于 2026-08-13 · 约 5 分钟阅读

外部化配置配置优先级命令行参数环境变量spring.config.locationSPRING_APPLICATION_JSON

本节目标:搞懂 Spring Boot 十几类配置来源的优先级顺序,学会用命令行、环境变量、外部文件覆盖配置。

什么是外部化配置

同一份代码,要跑在开发、测试、生产三个环境。

每个环境的数据库地址、端口都不一样。代码不能改,配置必须能变。

Spring Boot 的办法:配置全部「外部化」。启动时从十几个来源收集属性,按固定顺序合并。

顺序靠后来源的优先级更高,可以覆盖前面的值。

官方优先级顺序

以 Spring Boot 4.1.0 官方文档为准,完整顺序如下(从低到高):

  1. 默认属性:SpringApplication.setDefaultProperties(...) 设置的 Map。
  2. @PropertySource 注解引入的属性文件。
  3. 配置文件:jar 内的 application.properties / application.yml
  4. 随机值属性源:random.*
  5. OS 环境变量。
  6. Java 系统属性:System.getProperties()
  7. JNDI 属性:java:comp/env
  8. ServletContext 初始化参数。
  9. ServletConfig 初始化参数。
  10. SPRING_APPLICATION_JSON:内嵌 JSON 的环境变量或系统属性。
  11. 命令行参数。

测试场景还有 @TestPropertySource@DynamicPropertySource 等来源,优先级更高。日常开发记住前 11 条就够。

Warning

别背反了:列表越靠后,优先级越高。命令行参数是王者,能覆盖所有文件配置。

命令行参数

启动时用 -- 前缀传参,直接变属性:

java -jar hello-app.jar --server.port=9000 --spring.profiles.active=prod

开发时用 Maven 插件传:

mvn spring-boot:run -Dspring-boot.run.arguments="--server.port=9000"
Tip

-Dserver.port=9000 是系统属性,不是命令行参数,优先级低一档。两者写法不同,别混淆。

不想要命令行参数进 Environment,可以关掉:

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        SpringApplication application = new SpringApplication(Application.class);
        application.setAddCommandLineProperties(false);
        application.run(args);
    }
}

SPRING_APPLICATION_JSON

把一整块配置编码成 JSON,塞进一个变量:

SPRING_APPLICATION_JSON='{"server":{"port":9000},"app":{"name":"hello"}}' java -jar hello-app.jar

Windows 用 set 设置同名变量再启动即可。也支持系统属性和命令行参数形式:

java -Dspring.application.json='{"server":{"port":9000}}' -jar hello-app.jar

适合容器平台注入复杂配置的场景。

环境变量与系统属性

环境变量名不能带点和横线,Spring Boot 有转换规则:

  • 点换成下划线。
  • 横线去掉。
  • 全部转大写。

server.servlet.context-path 对应 SERVER_SERVLETCONTEXTPATH

spring.main.log-startup-info 对应 SPRING_MAIN_LOGSTARTUPINFO

Note

官方示例 SPRING_MAIN_LOGSTARTUPINFO 是去掉横线后的写法。很多教程写 SPRING_MAIN_LOG_STARTUP_INFO 也能绑上,因为下划线是分隔符;规则记「点变下划线、横线删除、全大写」最稳妥。

系统属性用法:

java -Dserver.port=9000 -jar hello-app.jar

配置文件的搜索位置

application.properties / application.yml 不止 classpath 一处。默认按顺序搜索:

  1. classpath 根目录。
  2. classpath 的 /config 目录。
  3. 当前目录。
  4. 当前目录的 config/ 子目录。
  5. config/ 的直属子目录(config/*/)。

后找到的覆盖先找到的。jar 外部的配置文件,天然能覆盖 jar 内部的默认值。

部署时把配置文件放在 jar 同目录的 config/ 下,是常见做法。

配置文件内部的加载顺序

光知道「配置文件」排第三优先级还不够。

配置文件自己还有一层顺序,从低到高:

  1. jar 内的 application.properties / application.yml(普通文件)。
  2. jar 外的 application.properties / application.yml(普通文件)。
  3. jar 内的 application-{profile} 变体。
  4. jar 外的 application-{profile} 变体。

结论:同位置下,profile 文件覆盖普通文件;jar 外覆盖 jar 内。

部署时把生产配置放到 jar 外,代码仓库里只留默认值,是最干净的分工。

spring.config.import 导入外部文件

2.4 起支持用 spring.config.import 引入额外配置。

在 application.yml 里声明:

spring:
  config:
    import: optional:file:./dev.properties

启动时会去当前目录找 dev.properties,找不到也不报错。

导入文件里的值,优先级高于触发导入的文件。

多个位置用逗号分隔,后面的覆盖前面的:

spring:
  config:
    import:
      - optional:file:./base.properties
      - optional:file:./override.properties
Note

optional: 前缀很重要。不加的话,文件不存在会让应用启动失败。

自定义文件名与位置

不想用 application 这个名字?用 spring.config.name

java -jar hello-app.jar --spring.config.name=myapp

指定外部配置文件位置:

java -jar hello-app.jar --spring.config.location=file:/etc/hello/config/

spring.config.location 会替换默认搜索位置。想保留默认位置、只追加,用 additional-location

java -jar hello-app.jar --spring.config.additional-location=file:/etc/hello/override.properties

位置不存在会启动失败。加 optional: 前缀容忍缺失:

java -jar hello-app.jar --spring.config.additional-location=optional:file:/etc/hello/override.properties
Tip

这几个键在启动极早期就要用,只能通过命令行参数、环境变量或系统属性传入,写进配置文件里不生效。

环境变量直接引用

配置文件里用 ${...} 引用环境变量,是容器部署的标配:

spring:
  datasource:
    url: ${DATABASE_URL}
    username: ${DB_USER:root}

:root 是默认值。环境变量没设置时用 root。

一个完整的覆盖例子

假设 jar 内配置:

server.port=8080
app.name=hello

部署命令:

export APP_NAME=hello-prod
java -jar hello-app.jar --server.port=9000

最终生效:端口 9000(命令行赢),应用名 hello-prod(环境变量赢)。

测试场景的属性来源

测试里还有几类更高优先级的来源:

  • @TestPropertySource 指定的属性文件。
  • @DynamicPropertySource 动态注册的属性。
  • @SpringBootTestproperties 属性。
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest(properties = {"server.port=0", "app.message=test"})
class ApplicationTests {
}

测试属性压过命令行参数,保证测试环境不被外部变量干扰。

配置排错

值不符合预期时,按优先级从高到低排查。Actuator 的 env 端点能看每个属性的最终值和来源:

curl http://localhost:8080/actuator/env

没启用 Actuator 的话,启动加 --debug 也能看到配置相关调试信息(条件报告详见 §6)。

小结

  • 外部化配置让同一份代码适配多环境。
  • 优先级从低到高:默认属性 → @PropertySource → 配置文件 → 环境变量 → 系统属性 → JNDI → Servlet 参数 → SPRING_APPLICATION_JSON → 命令行参数。
  • 环境变量名规则:点变下划线、去横线、全大写。
  • 外部配置文件用 spring.config.location / additional-location 指定。
  • 命令行参数是王者,能覆盖所有文件配置。
  • 同位置下 profile 文件覆盖普通文件,jar 外覆盖 jar 内。
  • spring.config.import 可以引入外部文件,记得加 optional:
  • 测试属性优先级最高,隔离测试环境。
  • 排错用 /actuator/env--debug