如果这篇文章对你有帮助欢迎关注我的CSDN账号「来福猿」 有问题可以在评论区留言我会一一回复。1. 引言SpringBoot 的「约定优于配置」让开发者可以快速启动一个应用但真正理解配置加载机制才能在多环境部署、配置覆盖和排障时做到心中有数。在 SpringBoot 应用启动时配置可能来自application.yml、命令行参数、环境变量、系统属性、随机值等多个来源。本文以 SpringBoot 2.x/3.x 的配置体系为背景从源码角度梳理配置加载流程重点分析 application.yml、命令行参数与环境变量三者的加载顺序、优先级以及背后的核心类。文中示例保持与 SpringBoot 原生技术栈一致便于读者直接对照源码调试。2. 配置来源与优先级SpringBoot 通过PropertySource来统一表示不同的配置来源最终把它们聚合到Environment中。常见的配置来源包括开发者工具中的全局配置测试环境中的TestPropertySource命令行参数例如--server.port8081SPRING_APPLICATION_JSON中的 JSON 属性ServletConfig初始化参数ServletContext初始化参数JNDI 属性Java 系统属性操作系统环境变量随机值应用外部配置例如application-dev.yml应用内部配置例如application.ymlPropertySource 注解加载的配置默认属性例如SpringApplication.setDefaultProperties从优先级角度看命令行参数优先级最高其次是系统属性、环境变量而应用内部的application.yml通常位于靠后的位置。也就是当多个来源同时配置同一个 key 时靠前的来源会覆盖靠后的来源。例如java -jar app.jar --server.port9090即使application.yml中写了server.port: 8080最终生效的端口仍然是9090因为命令行参数的优先级高于配置文件。3. 源码入口SpringApplication 与环境准备SpringBoot 应用的启动入口是SpringApplication.run方法。在run方法内部会先执行prepareEnvironment完成ConfigurableEnvironment的创建和配置源装配。public ConfigurableApplicationContext run(String... args) { // ... ApplicationArguments applicationArguments new DefaultApplicationArguments(args); ConfigurableEnvironment environment prepareEnvironment(listeners, applicationArguments); // ... }prepareEnvironment的核心逻辑如下private ConfigurableEnvironment prepareEnvironment( SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments) { ConfigurableEnvironment environment getOrCreateEnvironment(); configureEnvironment(environment, applicationArguments.getSourceArgs()); ConfigurationPropertySources.attach(environment); listeners.environmentPrepared(environment); // ... return environment; }其中configureEnvironment会进一步进行属性源配置并把命令行参数转成PropertySource加入环境。protected void configureEnvironment(ConfigurableEnvironment environment, String[] args) { if (this.addConversionService) { environment.setConversionService(new ApplicationConversionService()); } configurePropertySources(environment, args); configureProfiles(environment, args); }在这一阶段Environment只完成了基础属性源装载而application.yml等配置文件尚未被解析加载。4. 命令行参数解析ApplicationArguments 与 SimpleCommandLineArgsParser命令行参数是优先级最高的运营期配置来源适合通过部署脚本动态覆盖端口、日志级别等参数。SpringBoot 使用ApplicationArguments来统一表示命令行输入。默认实现是DefaultApplicationArguments它内部调用SimpleCommandLineArgsParser完成解析。解析结果分为两类选项参数以--开头例如--server.port8081。非选项参数不以--开头的普通参数。选项参数在后续会被包装为CommandLinePropertySource加入Environment。例如下面的启动命令java -jar app.jar --server.port9090 --logging.level.rootdebug会被解析成两组属性server.port9090 logging.level.rootdebug从源码看SpringApplication.configurePropertySources会执行如下逻辑protected void configurePropertySources(ConfigurableEnvironment environment, String[] args) { MutablePropertySources sources environment.getPropertySources(); if (!CollectionUtils.isEmpty(this.defaultProperties)) { DefaultPropertiesPropertySource.addOrMerge(this.defaultProperties, sources); } if (this.addCommandLineProperties args.length 0) { String name CommandLinePropertySource.COMMAND_LINE_PROPERTY_SOURCE_NAME; if (sources.contains(name)) { PropertySource? source sources.get(name); CompositePropertySource composite new CompositePropertySource(name); composite.addPropertySource( new SimpleCommandLinePropertySource(springApplicationCommandLineArgs, args)); composite.addPropertySource(source); sources.replace(name, composite); } else { sources.addFirst(new SimpleCommandLinePropertySource(args)); } } }可以看到命令行生成的SimpleCommandLinePropertySource通过addFirst被放到属性源列表的最前面这决定了它拥有最高优先级。5. 操作系统环境变量SystemEnvironmentPropertySource环境变量是容器化部署和云平台中最常用的配置注入方式例如 Kubernetes 的env、Docker 的-e参数。SpringBoot 在创建StandardServletEnvironment或StandardEnvironment时会把操作系统的环境变量包装成PropertySource。StandardEnvironment的构造过程如下public class StandardEnvironment extends AbstractEnvironment { public static final String SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME systemEnvironment; public static final String SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME systemProperties; Override protected void customizePropertySources(MutablePropertySources propertySources) { propertySources.addLast( new PropertiesPropertySource(SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME, getSystemProperties())); propertySources.addLast( new SystemEnvironmentPropertySource(SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, getSystemEnvironment())); } }在 Servlet 环境中StandardServletEnvironment还会在更靠前的位置加入servletConfigInitParams和servletContextInitParams。SystemEnvironmentPropertySource有一个重要特性它支持宽松绑定可以把环境变量名中的下划线自动映射成点号语法。例如环境变量SERVER_PORT可以直接匹配属性server.port。这一能力来自SystemEnvironmentPropertySource.resolvePropertyName方法。Override protected final String resolvePropertyName(String name) { Assert.notNull(name, Property name must not be null); String resolvedName checkPropertyName(name); if (resolvedName ! null) { return resolvedName; } String uppercasedName name.toUpperCase(); if (!name.equals(uppercasedName)) { String result checkPropertyName(uppercasedName); if (result ! null) { return result; } } return name; }也就是说即便我们不直接写server.port而是设置环境变量SERVER_PORTSpringBoot 依然能够识别并使用该值。6. application.yml 的加载流程虽然命令行参数和环境变量在prepareEnvironment阶段就进入Environment但application.yml要等到ConfigDataEnvironmentPostProcessor执行时才被读取。这个处理器在 SpringBoot 2.4 之后取代了旧版的ConfigFileApplicationListener承担配置文件定位、解析、激活 profile 等职责。6.1 ConfigDataEnvironmentPostProcessor核心入口是postProcessEnvironment方法Override public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) { postProcessEnvironment(environment, application.getResourceLoader(), application.getBootstrapRegistry()); } private void postProcessEnvironment(ConfigurableEnvironment environment, ResourceLoader resourceLoader, BootstrapRegistry bootstrapRegistry) { bootstrapRegistry.registerIfAbsent(ConfigDataLocationResolvers.class, this::createConfigDataLocationResolvers); ConfigDataEnvironment configDataEnvironment getConfigDataEnvironment(environment, resourceLoader, application.getConfigDataLocationResolverRegistry()); environment.getPropertySources().addLast( new ConfigDataEnvironmentPostProcessorPropertySource(configDataEnvironment)); }最终配置数据会被包装成ConfigDataEnvironmentPostProcessorPropertySource并追加到属性源列表末尾。因为它是addLast所以在默认情况下其优先级低于命令行参数、系统属性和环境变量。6.2 ConfigDataEnvironment 的创建与处理ConfigDataEnvironment在构造时会读取spring.config.import、spring.config.location等参数并确定默认的配置搜索路径。默认情况下SpringBoot 会按以下顺序搜索当前目录下的/config子目录当前目录classpath 下的/config包classpath 根目录配置文件默认名称是application默认扩展名包含.properties、.xml、.yml和.yaml。创建完成后processAndApply会驱动整个配置加载过程包括加载默认配置、无 profile 配置以及spring.profiles.active指定的 profile 配置。6.3 YAML 解析YamlPropertySourceLoaderapplication.yml的解析由YamlPropertySourceLoader完成。它的load方法会读取资源内容并使用 SnakeYAML 解析成PropertySource集合。public class YamlPropertySourceLoader implements PropertySourceLoader { Override public String[] getFileExtensions() { return new String[] { yml, yaml }; } Override public ListPropertySource? load(String name, Resource resource) throws IOException { ListMapString, Object loaded new OriginTrackedYamlLoader(resource).load(); if (loaded.isEmpty()) { return Collections.emptyList(); } ListPropertySource? propertySources new ArrayList(loaded.size()); for (int i 0; i loaded.size(); i) { String documentNumber (loaded.size() ! 1) ? (document # i ) : ; propertySources.add(new OriginTrackedMapPropertySource( name documentNumber, Collections.unmodifiableMap(loaded.get(i)), true)); } return propertySources; } }因此即使只有一份application.yml其多层嵌套结构也会被展平成形如spring.datasource.url的属性名。多文档语法则通过---分隔成不同的文档并分别生成属性源。6.4 Profile 配置的叠加当仅指定application.yml时SpringBoot 会先加载不带 profile 的配置再加载 profile 对应的配置例如application-dev.yml。后加载的配置可以覆盖先加载的配置中的同名属性。spring: profiles: active: dev它对应的加载顺序可以简化为application.ymlapplication-dev.yml如果配置分散在多个位置那么更靠近应用目录外部的配置具有更高优先级具体顺序与第 6.2 节中的搜索路径有关。7. 优先级总览与验证示例我们把三种本文重点关注的配置来源放到同一个应用里验证。配置文件如下server: port: 8080 app: name: config-demo启动时添加命令行参数和环境变量SERVER_PORT8081 APP_NAMEenv-value \ java -jar app.jar --server.port9090那么最终读取到的值会是属性application.yml环境变量命令行参数最终值server.port8080808190909090app.nameconfig-demoenv-value未设置env-value可以通过一个简单的CommandLineRunner输出验证SpringBootApplication public class ConfigDemoApplication { public static void main(String[] args) { SpringApplication.run(ConfigDemoApplication.class, args); } Bean CommandLineRunner runner(Environment environment) { return args - { System.out.println(server.port environment.getProperty(server.port)); System.out.println(app.name environment.getProperty(app.name)); }; } }运行结果印证了优先级顺序命令行参数 环境变量 application.yml。8. 关键类速查为了便于后续阅读源码下面整理本文涉及的关键类与其职责类名职责SpringApplication应用启动入口负责环境和上下文准备SimpleCommandLineArgsParser解析命令行参数SimpleCommandLinePropertySource命令行参数属性源SystemEnvironmentPropertySource环境变量属性源支持下划线宽松绑定ConfigDataEnvironmentPostProcessor驱动 application 配置文件的加载ConfigDataEnvironment定位并处理默认配置文件YamlPropertySourceLoader解析 yml/yaml 资源OriginTrackedMapPropertySource携带来源追踪信息的属性源9. 排障建议与实际应用在实际项目中使用多种配置来源时建议遵循以下原则默认配置入文件将稳定的默认值写入application.yml让仓库内配置保持语义清晰。环境差异用 profile使用application-dev.yml、application-prod.yml管理不同环境。敏感信息用环境变量数据库密码、第三方密钥等通过环境变量或密钥管理系统注入避免明文进入代码仓库。应急覆盖用命令行参数临时调整端口、开关或日志级别时使用--参数因其优先级最高且无需改动文件。当配置没有按预期生效时可以按以下顺序排查确认属性名是否与读取时使用的 key 完全一致注意 yml 中的层级展开。检查是否存在 profile 配置覆盖了默认配置。确认环境变量是否因下划线映射规则意外匹配了目标属性。确认命令行参数是否格式正确例如 key 和 value 之间应使用。在启动时通过 Actuator 的/actuator/env端点查看最终属性值与来源。10. 总结SpringBoot 的配置加载体系以PropertySource和Environment为核心通过「先聚合、后覆盖」的方式统一管理多种配置来源。命令行参数在prepareEnvironment阶段即被加装为最高优先级属性源环境变量由SystemEnvironmentPropertySource表示并支持下划线与点号的宽松绑定而application.yml的解析则由ConfigDataEnvironmentPostProcessor和YamlPropertySourceLoader在后续阶段完成。理解这三者的加载顺序与源码实现可以帮助我们在微服务、容器化部署和多环境切换场景中更加准确地控制配置行为也能在出现配置异常时快速定位问题来源。
企业数字化 ERP 产品动态
相关推荐
【Dify】智能旅行顾问应用 智能工具赋能旅行规划,自动化流程让信息查询与行程设计变得高效便捷。旅行顾问工作流围绕大语言模型和结构化节点设计,聚焦一站式智能出行建议生成,满足多样化的实际需求。
本文介绍该智能旅行顾问Demo的核心结构、流程机制与典型应用场景,解析关键节点与实际效果,帮助自… · 2026/9/24 17:46:00
华为OD机试真题 新系统 2026-09-09 C++【受限任务分配】 目录
题目
思路
Code
题目
题目内容:
某部门有一批待处理任务,数量为 x。系统按轮次处理任务,每次平分后只保留其中一组进入下一轮;当 x 等于 1 时处理结束。
当 x 为偶数时,执行一次平分,任务数变为 x 除以 2,消耗 1 点成本,操作次数增加 1。
当 x 为奇数时,… · 2026/9/24 17:46:00
开源本地 Agent OpenClaw 3.1.0,隐私可控的桌面自动化实操教程 📌 说明 本文基于 OpenClaw 版本展开讲解,全程采用图形化可视交互模式。整合包已内置全部运行依赖,普通使用者无需额外配置,即可完整复现整套部署流程。 ✨核心亮点: 全程可视化图形交互界面,自动补齐全部运… · 2026/9/24 17:46:00
COMSOL天然气水合物两相渗流模拟与文献复现全流程解析 天然气水合物,也就是大家常说的“可燃冰”,听起来离我们很远,但真做起相关实验和模拟来,又是另一回事了。我做这个课题最直观的感受是:在实验室里做天然气水合物两相渗流实验,成本高、周期长、重复性还差&a… · 2026/9/24 20:30:00
xarray与address_space:从页缓存索引到writeback的完整解析 做Linux内核开发和文件系统调优的人,迟早会跟struct xarray和struct address_space打交道。这两个结构一个管数据怎么按索引存取,一个管文件页缓存怎么落地,配合起来就是读写文件最核心的那条路。很多人第一次看源码时,看到addres… · 2026/9/24 20:30:00
Windows任务栏还原与设置大全:跑偏、消失、卡死一次解决 1. 咦,任务栏怎么跑上面去了? 很多人开机后突然发现,自己的任务栏不在屏幕底部了,而是跑到了屏幕的左侧、右侧或者顶部。更常见的是,明明昨天还好好的,今天一开机,任务栏就从下面“搬家”了。作… · 2026/9/24 20:30:00
9款AI论文辅助工具实测:开题报告高效写作完整指南 又是一年开题季。本科生写开题报告,最磨人的往往不是“写”本身,而是选题怎么收敛、文献哪里找、框架怎么搭、研究方法怎么选——这些环节既考验信息的检索和整理能力,又考验对研究逻辑的理解。2026年了,AI工具已经不再是“聊天玩… · 2026/9/24 20:30:00
AI治理五大技术路线:从规则配置到决策闭环的演进 1. 这不是又一个“AI治理”口号,而是数据团队正在经历的真实分水岭2026年刚开年,我连续参加了三场不同行业的数据治理闭门会——金融、制造、医疗各一场。有意思的是,每场开场前茶歇时,听到最多的一句话是:“你们用的哪… · 2026/9/24 20:29:54
隐马尔可夫模型(HMM)实战解析:时序解码与状态推断 1. 这不是数学游戏,是解决真实问题的“时间序列解码器” 你有没有遇到过这样的场景:手机语音助手听清了你每个字的发音,却把“我要订明天早上的高铁票”识别成“我要订明天早上的高贴票”;医院里,医生根据病人连续三天… · 2026/9/24 20:29:54
基于YOLOv8的渔船作业监控系统:从环境搭建到边缘部署全流程 简介:这是一套面向计算机、人工智能、自动化等专业学生与教师的毕业设计级项目资源,围绕YOLOv8实现渔船作业监控系统,可用于毕设、课程设计、大作业或项目立项演示。压缩包共97个文件,约24.21MB,以70个Python源码文件为… · 2026/9/24 0:00:13
1D-CNN时间序列建模实战:从Conv1d原理到工业落地 简介:面向时间序列数据建模的一维卷积神经网络完整实现,适合深度学习入门者及需要快速验证时序模型的研究者,能够从音频、文本、传感器或股价等序列中挖掘局部特征与时间依赖。压缩包体积很小,只有3KB,内含3个Python脚… · 2026/9/24 0:00:26
柔软的L:汉语语流中被忽视的舌肌张力控制 1. 这个“L”不是字母表里的L,而是舌尖上的L最近在几个方言群和语音教学社群里,反复看到有人发一句:“也说字母L:柔软的长舌”。初看以为是英语发音课笔记,点开才发现全是方言爱好者、播音系学生、语言康复师甚至戏曲演… · 2026/9/24 0:00:44