Spring Boot多环境配置:spring.profiles.active与include的区别与实操
做后端开发的人几乎都遇到过这类需求同一套代码要同时部署到开发、测试、生产等不同环境每个环境的数据库地址、日志级别、缓存连接、第三方接口密钥可能完全不同。Spring Boot 的标准解法是 profile而在实际项目里最常碰到的两个配置就是spring.profiles.active和spring.profiles.include。这两个属性名字太像了很多人误以为它们是同一个东西的两种写法其实语义完全不同。spring.profiles.active负责“选主环境”spring.profiles.include负责“往当前环境里追加公共配置”。如果分不清这一点非常容易出现配置被覆盖、include 不生效、环境串配置的诡异问题。这篇文章就把这两行属性的实现逻辑、加载顺序、常见误区和实操配置完整讲一遍。我尽量用项目里真实会遇到的例子来说明而不是只贴语法。无论你是在维护一个老项目还是刚开始给新服务做多环境配置这几点都值得花几分钟看明白。1. 先从整体上理解这两行配置是干什么的1.1 多环境带来的配置管理麻烦在没有 profile 机制的年代我们切换环境往往是直接改配置文件或者维护多套 properties 文件打包时手动换一份。这个做法的最大问题是容易漏改、容易改错、还容易在合并代码时把生产配置一起提交上去。后来大家开始用 Maven 的 profile 做资源过滤用-Pdev这类参数在构建时替换配置文件。这套方案也能跑但它把“环境切换”提前到了编译阶段。真正发布到服务器上的 jar 已经是固定环境的产物运维想临时调整环境就非常不方便。Spring Boot 的 profile 不一样。它是在应用启动阶段根据spring.profiles.active决定加载哪些配置片段环境是运行时决定的而不是构建期决定。所以同一个 jar 包开发时用--spring.profiles.activedev启动生产上用--spring.profiles.activeprod启动不需要重新打包。这一点是解决多环境问题的核心思路。1.2 active 是“主开关”include 是“必含项”spring.profiles.active就是我们常说的“激活 profile”。比如你写了spring.profiles.activedev意味着应用会加载application-dev.yml里的配置同时dev这个环境标识会在整个应用上下文里生效。spring.profiles.include的意思则是“无论当前激活了哪个主环境我也要无条件加入这些 profile”。比如在application.yml里写spring: profiles: include: common, security那么启动时不管active指定的是dev还是prodcommon和security这两个 profile 都会被加载。include 里的配置通常放一些所有环境都需要的公共内容比如基础数据源、通用安全规则、全局过滤器等。从语义上看active 是“我这次运行主要用哪个环境”include 是“这些配置无论如何都给我带上”。两者是主从关系不是平级关系。1.3 为什么不能只靠 active 解决有人可能会问既然可以用逗号分隔为什么不直接写成spring.profiles.activedev,common,security我遇到过不少这么干的同事刚开始看着没问题后面维护起来就暴露了问题。主环境是dev、test、prod公共配置是common、security、logging。如果全部写在 active 里每次切换环境都要写一串很长的环境名很容易漏写common。一旦漏掉运行时就会出现一些难以定位的缺失配置。用 include 的好处在于公共配置与主环境解耦。你在application.yml顶层声明一次所有环境自动带上。后续新增一个环境只需要定义自己的主 profile 文件不用惦记 include 里那堆东西。2. 生效顺序与覆盖规则这一块最容易踩坑2.1 配置加载顺序的底层逻辑要理解 active 和 include 的区别核心是理解 Spring Boot 加载配置的顺序。官方文档和实际代码都表明profile 相关的处理实际上分两个阶段先处理spring.profiles.active指定的 profile。再处理spring.profiles.include包含的 profile。这个顺序非常关键。它意味着如果active和include里出现同一个配置项active会覆盖include。官方也明确说过include 的设计初衷就是不让它反过来覆盖 active。用一个场景说明。假设有这两个文件# application-common.yml server: port: 7070# application-dev.yml server: port: 8080启动参数是--spring.profiles.activedev --spring.profiles.includecommon最终生效的端口是8080因为dev属于 activecommon属于 includeactive 的优先级更高。如果你期望的是common覆盖dev那这个设计会直接让你失望。2.2 active 与 include 冲突时的取舍实际项目里我建议尽量不要让 include 和 active 里的配置项产生重叠。如果确实需要覆盖要有意识地区分优先级。一种常见做法是include 里放的是“缺省值”或“兜底配置”active 里放的是“环境专属覆盖值”。比如把通用超时时间放在application-common.ymlrequest: timeout: 3000然后某个专门处理长任务的task主环境放在application-task.ymlrequest: timeout: 15000这样的结果是跑 task 环境时超时时间被覆盖为 15 秒跑其他环境时用 3 秒兜底。这个用法是 include 比较理想的一种场景。2.3 include 放在不同位置效果完全不一样这是新手特别容易忽略的点。spring.profiles.include可以出现在不同层级的配置里但效果差别很大。如果放在application.yml顶层它就是一个“全局必含项”。不管 active 是什么include 都会生效。这点前面已经说过。如果放到某个 profile-specific 文件里比如application-dev.yml那么在Spring Boot 2.4 之前的版本它只会在激活dev时被处理。例如# application-dev.yml spring: profiles: include: common这段配置意味着只有当你激活dev时common才会被额外加载。激活prod时这段 include 不会执行因为prod不加载application-dev.yml。但在Spring Boot 2.4 之后这种写法已经不可靠了。官方在配置加载重构时明确过不再支持在 profile-specific 文件中动态添加 include。如果你用了 2.4 版本还想做条件化的分组加载应该使用spring.profiles.group而不是在application-dev.yml里写 include。这个变化我在后面专门讲。2.4 命令行参数、环境变量与配置文件的优先级spring.profiles.active和spring.profiles.include也可以通过命令行参数和环境变量传入。它们遵循 Spring Boot 常规的配置优先级命令行参数 Java 系统属性 操作系统环境变量 application-{profile}.yml application.yml 默认 profiles。我常用的启动方式是这样java -jar app.jar --spring.profiles.activeprod --spring.profiles.includecommon命令行参数写法简单适合本地联调和测试环境。部署到服务器时我更喜欢用环境变量export SPRING_PROFILES_ACTIVEprod export SPRING_PROFILES_INCLUDEcommon startup.shSpring Boot 的环境变量映射规则是把点号换成下划线、大写SPRING_PROFILES_ACTIVE对应spring.profiles.activeSPRING_PROFILES_INCLUDE对应spring.profiles.include。这里要特别注意环境变量的优先级比application.yml里的 include 更高。也就是说哪怕配置文件里写死了 include只要环境变量里显式设置了SPRING_PROFILES_INCLUDE就会以环境变量为准。这个机制在容器化部署时很有用可以不用改动代码和配置文件直接在部署平台上注入环境变量切换环境。3. 从零搭建一套可用的 profile 切换方案3.1 文件结构怎么规划我建议普通项目按照“基础配置 公共模块 环境配置”三组来组织文件。不要把所有内容都堆在application.yml里也不要让 profile-specific 文件之间互相依赖太多。一套比较清晰的目录结构是这样的src/main/resources/ ├── application.yml ├── application-common.yml ├── application-security.yml ├── application-logging.yml ├── application-dev.yml └── application-prod.ymlapplication.yml只放应用名、基础编码、以及spring.profiles.include这样的全局开关。application-common.yml放所有环境通用的数据源、缓存、MQ 连接等。application-security.yml放通用的安全配置。application-logging.yml放全局限流和日志格式。环境专属文件只放当前环境自定义的部分。这样做的好处是每个文件的职责单一。排查问题时只需要根据启动日志里加载了哪些 profile直接定位到对应文件不用在几个大文件之间来回翻滚。3.2 三种常用启动方式第一种是本地开发直接指定参数这也是最简单的测试方式java -jar order-service.jar --spring.profiles.activedev第二种是服务器上的 shell 脚本用环境变量注入export SPRING_PROFILES_ACTIVEprod exec java -jar order-service.jar第三种是测试环境分支固定比如在 CI 流水线里设置好环境变量让每次构建产物共用一个 jar然后根据部署环境传入不同的 profile。这种方式最符合“一次构建、多处运行”的思路。我在实际项目里还见过一种用法在 test 环境启动时把 include 也通过命令行传入用来临时加载一个只放模拟数据的 mock profile。这样不需要改动正式配置也不需要新增环境文件。3.3 完整示例某订单系统的 dev 与 prod 切换我拿一个虚构的订单服务来演示完整配置。假设这个服务需要数据库、Redis、消息队列三种基础依赖并且不同环境连接地址不一样。application.yml顶层spring: application: name: order-service profiles: include: common, loggingapplication-common.ymlspring: datasource: url: jdbc:mysql://localhost:3306/order_default username: root password: root redis: host: localhost port: 6379application-logging.ymllogging: pattern: console: %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%napplication-dev.ymlspring: datasource: url: jdbc:mysql://192.168.1.10:3306/order_dev username: dev_user password: dev_pass redis: host: 192.168.1.20application-prod.ymlspring: datasource: url: jdbc:mysql://10.20.30.40:3306/order_prod username: prod_user password: prod_pass redis: host: 10.20.30.50当使用--spring.profiles.activedev启动时实际加载的知识点是application.yml声明 include common, logging所以common和logging都会激活同时dev作为 active 激活。这样最终 profile 集合是dev, common, logging。由于 active 优先application-dev.yml中定义的数据库配置会覆盖application-common.yml中的默认数据库配置。当使用--spring.profiles.activeprod启动时加载的 profile 集合是prod, common, logging数据库走生产地址公共模块仍然是同一份。这个结构维护几个月后你会明显感觉到比把所有环境参数都堆在一个 active 列表里要轻松。4. 常见问题速查与排查技巧4.1 include 完全不生效配置没加载如果你启动时发现application-common.yml的内容根本没被加载大概率是 include 的位置写错了。常见错误是把 include 写进了application-{profile}.yml然后期望它全局生效。例如在application-dev.yml里写spring: profiles: include: common然后你用--spring.profiles.activetest启动此时test只加载application-test.yml根本不会去读application-dev.yml中的 include自然就没有common。如果想全局生效应该把 include 放到application.yml顶层。如果确实希望只有某个环境激活时才包含额外 profile建议用 profile group 的方案而不是依赖 profile-specific 文件里的 include。问题排查看启动日志最直接。Spring Boot 启动时会输出The following 3 profiles are active: dev, common, logging如果common不在这个列表里说明 include 没被解析到直接去检查配置文件位置和拼写。4.2 include 和 active 里同一个 key 冲突结果不是我想要的这个场景我在前面说过了。假设common里定义了server.port7070dev里定义了server.port8080启动 activedev、includecommon最终生效的是 8080。如果预期是相反结果那就不是 include 的用法不对而是对优先级理解不一致。判断优先级有一个简单办法把 active 里的 profile 看成“此次运行的主角”include 里的 profile 看成“配角”。配角提供基础内容主角可以覆盖配角。如果你希望某个公共配置无论如何都不能被覆盖必须在 active 环境里避开同 key 的重定义。另外多个 include profile 之间如果出现同名配置顺序也会影响结果。比如 include 是common, base而两个文件都定义server.port后解析的那个文件会覆盖先解析的。这种隐式顺序是最难排查的所以我强烈建议 include 的不同 profile 各自负责独立的配置域不要交叉定义同一个属性。4.3 Spring Boot 2.4 前后的行为差异如果你最近在做版本升级务必留意 include 的差异。Spring Boot 2.4 重构了配置加载机制有些以前能跑的写法在新版本里会失效。核心变化是在 Spring Boot 2.4 之前你可以在application-dev.yml中使用spring.profiles.include来追加其他 profile2.4 之后这种做法不再被支持如果仍然那么写大概率不会按预期加载。替代方案是使用spring.profiles.groupspring: profiles: group: dev: common, logging prod: common, logging然后在启动时只要指定--spring.profiles.activedev就会按组展开成dev, common, logging。这个语义更清晰也避免了很多 include 放在 profile-specific 文件里造成的隐性问题。还在维护老版本项目的读者建议尽快评估升级否则这种旧写法会阻碍你后续用上 2.4 之后的配置新特性。4.4 排查手段与速查表遇到 profile 相关问题时我一般按以下顺序排查看启动日志确认实际激活的 profile 列表。用actuator/env接口查看当前生效配置来源确认配置值来自哪个文件。检查 include 是否放在正确层级。检查版本差异确认是否有 2.4 后行为变更。最后再看同一个 key 在多少文件里被重复定义。场景推荐处理方式全局公共配置所有环境都要加载放在application.yml顶层 include或使用 profile group仅某环境要加载额外配置使用 2.4 的 profile group 更合理需通过运维调整 include用环境变量SPRING_PROFILES_INCLUDE注入active 和 include 同名配置以 active 为准不要期望 include 覆盖老版本项目升级后 include 失效改用 group 并把 include 从 profile-specific 文件移到主文件我个人在实际操作中的体会是配置文件的维护难点往往不是语法而是“看起来每个文件都对但整体行为不是预期”。把 active 和 include 的职责边界划清楚比记住各种参数写法重要得多。最后再分享一个小技巧每次启动新服务时在日志里确认一遍 “The following profiles are active” 这一行几秒钟就能避免大量环境错配问题。

相关新闻

text-to-cad 实战:从自然语言到可制造三维模型

text-to-cad 实战:从自然语言到可制造三维模型

1. 从一句话到三维模型:text-to-cad 到底在解决什么问题第一次听到 "text-to-cad" 这个说法,很多人脑子里冒出来的画面是:对着电脑说一句"给我画个支架",屏幕上就自动长出一个带孔位的三维零件。这个想象不算…

2026/10/10 7:16:17 阅读更多 →
GDPR数据泄露检测自动化测试方案:从合规条款到工程实践

GDPR数据泄露检测自动化测试方案:从合规条款到工程实践

1. 为什么GDPR合规必须依赖自动化测试:从72小时通知义务说起做数据合规的人都知道,GDPR第33条有一个让安全团队如坐针毡的要求:一旦发生个人数据泄露,必须在72小时内向监管机构通报。这个时间窗口不只是算上发现时间,而…

2026/10/10 7:15:16 阅读更多 →
Codex CLI接入OpenAI兼容接口:config.toml配置与排错

Codex CLI接入OpenAI兼容接口:config.toml配置与排错

如果你手头有 Codex CLI,又不想只接固定的云上模型,今天这篇文章值得你花五分钟看完。我会把config.toml逐行拆开讲,覆盖接入 OpenAI 兼容接口时的常见报错和排查思路,也算是我这半年反复折腾下来的一份笔记。文章面向两类人&…

2026/10/10 7:15:16 阅读更多 →

最新新闻

C语言进阶实战:从环境配置到项目开发的完整指南

C语言进阶实战:从环境配置到项目开发的完整指南

这篇《C语言学习6》写的时候,我心里挺有感触的。前面五篇把基本语法、分支循环、数组函数都过了一遍,但真正从“看懂”变成“会写”,靠的还是这段时间反复踩坑、反复调试的积累。这篇不打算再堆语法知识点,而是把这一阶段让我印象…

2026/10/10 9:37:44 阅读更多 →
超市进销存管理系统源码实战:从跑通到生产级避坑指南

超市进销存管理系统源码实战:从跑通到生产级避坑指南

简介:这份超市进销存管理系统源码面向Java初学者与中小零售项目开发者,帮助理解采购、销售、库存等核心业务在代码层面的落地方式。系统涵盖登录验证、销售订单增删改查、商品统计报表等模块,源码中可见销售单、进货单、退货单及入库查询等业…

2026/10/10 9:37:44 阅读更多 →
数据结构C语言课设完整实现:从Makefile到可运行工程

数据结构C语言课设完整实现:从Makefile到可运行工程

简介:这是一份面向计算机专业学生与C语言学习者的数据结构课程设计完整源码包,围绕单链表、栈、队列、二叉树与图五种核心结构展开,通过多级菜单串联各模块的基本操作与典型应用,适合课程设计参考、期末复习与算法入门练手。压缩包…

2026/10/10 9:37:44 阅读更多 →
Node.js Worker线程自动重启:从无声崩溃到生产级自愈方案

Node.js Worker线程自动重启:从无声崩溃到生产级自愈方案

去年处理一个图片缩略图服务时,我遇到了一个很诡异的事:任务队列突然卡死,积压了几万条消息,主进程的CPU和内存却完全正常,监控面板上唯一的异常是——某个worker线程不见了。最后排查发现,worker里一段不起…

2026/10/10 9:37:43 阅读更多 →
SpringBoot医药知识推荐平台毕设实战:从推荐算法到系统部署

SpringBoot医药知识推荐平台毕设实战:从推荐算法到系统部署

每年毕业季,计算机专业的毕设选题里,“SpringBoot XX管理系统”绝对是出现频率最高的组合。但如果你选的题目是“医药知识推荐平台”,光会写增删改查那一套还真不够——推荐功能才是这个项目的灵魂。我最近正好完整复盘了一个编号为13126的S…

2026/10/10 9:37:43 阅读更多 →
出海实战避坑指南:用好Ask Me专家资源,少走弯路

出海实战避坑指南:用好Ask Me专家资源,少走弯路

出海这件事,这几年真的被太多人问过了。见得多了之后我发现一个规律:大多数出海踩坑的团队,不是不够拼,而是“问错了人”或者“没问到点子上”。所以当看到“出海有问题,尽管Ask Me!2026出海实战专家已就位…

2026/10/10 9:36:42 阅读更多 →

日新闻

卫星轨道分类全解析:从LEO到GEO的选型逻辑与工程实践

卫星轨道分类全解析:从LEO到GEO的选型逻辑与工程实践

1. 从“卫星轨道分类”这个标题说起:为什么值得花时间搞懂第一次接触“卫星轨道分类”这个概念,很多人会觉得它离自己很远——不就是天上的星星怎么转吗?但如果你正在做航天任务规划、遥感数据接收、星座设计,甚至只是准备一场航天…

2026/10/10 0:00:39 阅读更多 →
Spring AOP 核心原理与实战:从概念到日志切面落地

Spring AOP 核心原理与实战:从概念到日志切面落地

1. 从一个真实痛点说起:为什么你的代码里到处都是重复逻辑刚入行那会儿,我写过一个用户管理模块,注册、登录、改密码、注销四个接口。每个接口里都塞了几乎一样的日志打印、参数校验、事务开启和提交。当时觉得没什么,能跑就行。直…

2026/10/10 0:00:40 阅读更多 →
Python招聘数据采集与分析可视化:从采集清洗到薪资技能城市可视化全链路

Python招聘数据采集与分析可视化:从采集清洗到薪资技能城市可视化全链路

简介:这是一套面向计算机相关专业学生与项目实战学习者的Python数据采集与分析可视化完整项目,以Boss直聘岗位数据为对象,适合用作毕业设计、课程设计或期末大作业。资源包共38个文件,约246KB,以13个py源码文件为核心&…

2026/10/10 0:00:40 阅读更多 →

周新闻

KT148A语音芯片外挂8002D功放的工程实践指南

KT148A语音芯片外挂8002D功放的工程实践指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/8 15:26:32 阅读更多 →
LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/10 1:36:08 阅读更多 →
ARM架构深度解析:从RISC设计理念到交叉编译实战

ARM架构深度解析:从RISC设计理念到交叉编译实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/9 10:11:06 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/10 5:23:50 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/9 21:32:20 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/9 6:17:20 阅读更多 →