返回

SpringBoot 外部配置文件的使用和优先级

SpringBoot 提供了灵活的外部配置机制,让我们无需重新打包就能调整应用行为。本文梳理了几种常用的外部配置方式及其优先级关系,帮你在不同部署场景下做出正确选择。

改个端口号,还要重新打包?

你一定遇到过这种场景:项目打成 jar 包部署到服务器上,结果发现端口号冲突了,或者数据库地址要换。难道就为了改一行配置,要重新走一遍构建流程?当然不用。

SpringBoot 早就考虑到了这个问题,它提供了多种外部配置方式,让同一个 jar 包可以在不同环境中灵活运行。掌握这些配置方法和它们的优先级关系,是每个 SpringBoot 开发者的必备技能。

三种配置方式对比

在深入细节之前,先看一下各方式的适用场景:

配置方式适用场景优点缺点
命令行参数临时调试、启动多实例即时生效,无需改文件参数多时命令行冗长
环境变量Docker/K8s 容器化部署配置与代码解耦不易管理大量配置
外部配置文件生产环境、多配置项集中管理,支持多环境需维护文件同步

方式一:命令行参数

最简单粗暴的方式,直接在启动命令里加参数:

nohup java -jar myapp.jar --server.port=8081

这种方式适合临时调整,比如排查问题时临时换个端口,或者在不同终端启动多个实例。缺点也很明显——参数一多,命令行就变得又臭又长。

方式二:环境变量

在容器化部署(Docker、K8s)的场景下,环境变量是最主流的配置方式:

export SERVER_PORT=8081
java -jar myapp.jar

SpringBoot 会自动把环境变量映射到对应的配置属性上。映射规则很简单:把属性名中的点换成下划线,字母全大写。

配置属性对应环境变量
server.portSERVER_PORT
spring.datasource.urlSPRING_DATASOURCE_URL
spring.redis.hostSPRING_REDIS_HOST
app.jwt.secretAPP_JWT_SECRET

这种方式的好处是配置和代码完全解耦,特别适合 12-Factor App 的理念1

方式三:外部配置文件

当需要修改的配置项比较多时,外部配置文件是最合适的选择。

SpringBoot 支持多种配置文件格式,包括 application.propertiesYAML.yml)以及 TOML(SpringBoot 3.2+)。

放在 jar 包同级目录

最省事的做法:在 jar 包所在目录创建 application.ymlapplication-{profile}.yml,SpringBoot 启动时会自动加载它,并且优先级高于 jar 包内部的同名文件。

指定配置文件路径

如果配置文件放在别的目录,用 --spring.config.location 来指定:

java -jar myapp.jar --spring.config.location=file:/path/to/application.yml

追加额外配置

有时候你不想替换默认配置,只想在默认基础上加一些覆盖项。这时候用 --spring.config.additional-location

java -jar myapp.jar --spring.config.additional-location=file:/path/to/application-prod.yml --spring.profiles.active=prod

[!WARNING] locationadditional-location 的区别很关键:location完全替换默认的配置搜索路径,而 additional-location 是在默认路径之外追加。搞混了会导致很多默认配置突然失效,排查起来非常头疼。

配置加载优先级

说了这么多配置方式,那它们之间冲突了怎么办?SpringBoot 有一套明确的优先级规则(从高到低):

graph TD
    A["① 命令行参数\n--server.port=9090"] --> B["② Java 系统属性\n-Dserver.port=9090"]
    B --> C["③ 环境变量\nSERVER_PORT=9090"]
    C --> D["④ 外部 profile 配置\napplication-prod.yml"]
    D --> E["⑤ 外部默认配置\napplication.yml"]
    E --> F["⑥ 内部 profile 配置\nresources/application-prod.yml"]
    F --> G["⑦ 内部默认配置\nresources/application.yml"]
    style A fill:#ef4444,color:#fff,stroke:none
    style G fill:#3b82f6,color:#fff,stroke:none

用表格形式总结一下:

优先级配置来源示例
1(最高)命令行参数--server.port=9090
2Java 系统属性-Dserver.port=9090
3操作系统环境变量export SERVER_PORT=9090
4外部 profile 配置文件jar 同级目录的 application-prod.yml
5外部默认配置文件jar 同级目录的 application.yml
6内部 profile 配置文件resources/application-prod.yml
7(最低)内部默认配置文件resources/application.yml

核心原则就一句话:越「外部」的配置,优先级越高。命令行参数最高,jar 包内部的配置文件最低。同名属性会被高优先级的覆盖,不同名的则会合并。

[!NOTE]

  • --spring.config.location 会完全替换默认的配置位置,用的时候要小心
  • --spring.config.additional-location 是追加,不会影响默认配置的加载
  • 后加载的配置会覆盖先加载的同名配置

如何验证哪个配置生效了?

配置来源一多,难免会遇到”我明明改了,怎么没生效”的情况。这里分享几个诊断方法。

启用 debug 模式

在启动命令里加 --debug,SpringBoot 会打印出所有配置源的加载顺序:

java -jar myapp.jar --debug

启动日志中会出现 PropertySource 相关的信息,告诉你每个配置值来自哪里。

使用 Actuator 端点

如果项目引入了 spring-boot-starter-actuator,可以通过 /actuator/env 端点查看所有生效的配置及其来源:

curl http://localhost:8080/actuator/env/server.port

[!TIP] 生产环境记得用 Spring Security 保护 Actuator 端点,不要把配置信息暴露给外部。

代码中打印

最简单粗暴的方式,在启动类里直接打印关键配置值:

@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        var ctx = SpringApplication.run(Application.class, args);
        var env = ctx.getEnvironment();
        log.info("server.port = {}", env.getProperty("server.port"));
        log.info("active profiles = {}", Arrays.toString(env.getActiveProfiles()));
    }
}

多环境配置最佳实践

实际项目中,通常会有 dev、test、prod 等多套环境。我的经验是这样组织:

jar 包内部只放通用的默认配置和开发环境配置:

resources/
├── application.yml           # 通用默认配置
├── application-dev.yml       # 开发环境(默认激活)

服务器上通过外部配置文件覆盖环境相关的值:

/opt/app/
├── myapp.jar
├── application-prod.yml      # 生产环境配置(数据库、Redis 等)

启动命令:

java -jar myapp.jar --spring.config.additional-location=file:./application-prod.yml --spring.profiles.active=prod

[!IMPORTANT] 敏感配置(数据库密码、JWT 密钥等)不要写进代码仓库。生产环境的配置文件应该只存在于服务器上,或者通过配置中心(如 Nacos)统一管理。

配置管理检查清单

  • jar 包内部只保留通用默认配置和开发环境配置
  • 生产环境敏感配置(密码、密钥)不提交到代码仓库
  • 外部配置文件放在 jar 包同级目录或通过 --spring.config.additional-location 指定
  • 使用 --spring.profiles.active 明确指定当前环境的 profile
  • 通过 Actuator /actuator/env 端点验证配置是否正确生效
  • Actuator 端点已配置 Spring Security 访问控制
  • 多实例部署时确保配置文件版本一致,避免配置漂移

小结

回到开头的问题——改配置不需要重新打包,只需要选择合适的外部配置方式。日常开发中,我的习惯是:开发环境用 jar 包内部的默认配置,测试和生产环境通过外部配置文件覆盖,临时调试用命令行参数。理解了优先级规则,配置管理就不会乱。更多配置机制的细节可参考 Spring Boot 官方文档 - Externalized Configuration

Footnotes

  1. 12-Factor App 是 Heroku 团队提出的构建 SaaS 应用的方法论,其中第三条原则「在环境中存储配置」主张将配置与代码严格分离,通过环境变量注入配置信息,从而实现同一份代码在不同环境中运行。