一、先搞懂:什么是profile?为什么需要多配置文件?
1.profile的通俗定义
profile就是SpringBoot为多环境配置设计的「环境标签」,可以把不同环境(开发、测试、生产)的配置分开管理,给每套配置打一个标签(比如dev、test、prod),启动项目时指定要使用的标签,SpringBoot就会自动加载对应标签的配置,实现环境配置隔离。
简单说:profile就是给配置文件「分组」,开发用dev组、测试用test组、生产用prod组,互不干扰,不用手动改配置文件。
2. 为什么需要多配置文件?
开发中最常见的痛点:开发环境和生产环境的配置不一样,比如:
- 开发环境连本地数据库,生产环境连线上数据库;
- 开发环境端口8080,生产环境端口80;
- 开发环境开启日志调试,生产环境关闭调试、只打错误日志。
如果把所有配置写在一个文件里,每次部署生产都要手动修改,容易出错还麻烦;用profile分文件管理,只需启动时指定环境,全程不用改配置,优雅又安全。
3.profile的核心命名规范
SpringBoot对多环境配置文件有强制命名规则,必须遵守,否则无法识别:
# properties格式 application-{profile}.properties # 环境专属配置,{profile}是你的环境标签(dev/test/prod) application.properties # 全局公共配置(所有环境都共用的配置) # yml格式(更常用,简洁) application-{profile}.yml application.yml默认环境:如果不指定任何profile,SpringBoot会默认使用default环境,加载application.yml/properties(可以理解为application-default.yml的简写)。
二、profile的基础用法:定义+激活(先会用,再讲原理)
先通过最简示例掌握核心用法,后续的加载位置/优先级都是基于这个基础展开,示例用yml格式(生产主流,properties格式同理)。
步骤1:定义多环境配置文件
在SpringBoot项目的src/main/resources下,创建3个配置文件(1个公共+2个环境专属):
- application.yml:全局公共配置(所有环境都用,比如应用名称、全局描述)
- application-dev.yml:开发环境配置(本地开发,比如本地数据库、8080端口)
- application-prod.yml:生产环境配置(线上部署,比如线上数据库、80端口)
示例配置
1. 公共配置:application.yml
# 所有环境共用的配置spring:application:name:springboot-profile-demo# 应用名称,全局唯一# 公共日志配置(所有环境都用)logging:level:root:info2. 开发环境:application-dev.yml
# 开发环境-本地配置server:port:8080# 开发端口8080spring:datasource:url:jdbc:mysql://localhost:3306/dev_db?useUnicode=true&characterEncoding=utf8username:rootpassword:123456# 本地数据库密码3. 生产环境:application-prod.yml
# 生产环境-线上配置server:port:80# 生产端口80spring:datasource:url:jdbc:mysql://192.168.1.100:3306/prod_db?useUnicode=true&characterEncoding=utf8username:prod_userpassword:Prod@123456# 线上数据库密码(复杂)步骤2:激活指定的profile(核心)
定义好多环境配置后,需要告诉SpringBoot启动时用哪个环境,这就是「激活profile」,SpringBoot提供4种激活方式,按开发常用程度排序,覆盖「开发调试」和「生产部署」场景。
方式1:在全局配置文件中激活(开发时最常用,直接写在application.yml里)
在application.yml中添加spring.profiles.active,指定要激活的环境标签,比如激活dev:
# 公共配置spring:application:name:springboot-profile-demoprofiles:active:dev# 激活开发环境,改成prod就是激活生产环境logging:level:root:info优点:开发时只需改这一个地方,切换环境方便;缺点:生产时如果打包到jar里,需要改代码重新打包,适合开发/测试环境,不适合生产。
方式2:通过命令行参数激活(生产环境最常用,推荐!)
项目打成jar包后,启动时通过--spring.profiles.active指定环境,无需修改配置文件,动态切换,这是生产部署的标准用法:
# 激活开发环境java -jar springboot-profile-demo.jar --spring.profiles.active=dev# 激活生产环境(生产常用)java -jar springboot-profile-demo.jar --spring.profiles.active=prod# 同时激活多个环境(比如基础配置+生产配置,后面的覆盖前面的)java -jar xxx.jar --spring.profiles.active=base,prod核心优势:包可复用,同一个jar包可以部署到开发/测试/生产环境,只需改命令行参数,符合生产规范。
方式3:通过JVM参数激活
启动时通过-Dspring.profiles.active指定环境,本质是设置JVM系统属性,和命令行参数类似,适合部署在Tomcat等容器的场景:
# JVM参数在前,jar包在后java -Dspring.profiles.active=prod -jar springboot-profile-demo.jar方式4:通过系统环境变量激活
在服务器上设置系统环境变量SPRING_PROFILES_ACTIVE,SpringBoot会自动读取,适合固定环境的服务器(比如测试服务器永久用test环境):
- Windows:
set SPRING_PROFILES_ACTIVE=prod - Linux/Mac:
export SPRING_PROFILES_ACTIVE=prod
设置后直接启动jar包,无需加任何参数,SpringBoot会自动加载prod环境:
java -jar springboot-profile-demo.jar额外技巧:yml的多文档块(单文件实现多环境,适合简单项目)
如果项目环境配置比较简单,不想创建多个yml文件,可以在同一个application.yml中用---(分隔符)划分多文档块,每个文档块对应一个环境,用spring.profiles指定标签,spring.profiles.active激活。
示例:单文件实现dev/prod
# 第一文档块:全局公共配置(默认环境)spring:application:name:springboot-profile-demoprofiles:active:dev# 激活开发环境logging:level:root:info---# 分隔符,开始新的文档块# 第二文档块:开发环境,指定标签devspring:profiles:devserver:port:8080spring:datasource:url:jdbc:mysql://localhost:3306/dev_dbusername:rootpassword:123456---# 分隔符,开始新的文档块# 第三文档块:生产环境,指定标签prodspring:profiles:prodserver:port:80spring:datasource:url:jdbc:mysql://192.168.1.100:3306/prod_dbusername:prod_userpassword:Prod@123456注意:yml多文档块的---必须顶格写,分隔符前后的文档块相互独立,适合配置少的小项目;配置多的项目建议还是分文件管理,可读性更高。
三、核心重点:配置文件的加载位置(内置+外部)
SpringBoot启动时,会从多个固定位置自动扫描并加载application.yml/properties和application-{profile}.yml/properties,这些位置分为两大类:
- 内置配置:项目内部的配置文件,放在
src/main/resources下,打包后会被打入jar包中; - 外部配置:项目外部的配置文件,放在jar包所在的服务器目录中,不打入jar包,生产环境优先用(方便修改,不用重新打包)。
SpringBoot官方规定了10个默认加载位置(按优先级从低到高排序,后面会讲优先级),日常开发/生产中只用前6个核心位置就够了,我会标清「常用程度」和「使用场景」,不用记全,记核心的就行。
先明确两个基础路径标识
classpath::代表项目的类路径,就是开发时的src/main/resources目录,打包后是jar包内部的/BOOT-INF/classes/目录(内置配置的核心路径);./:代表当前目录,就是启动jar包时,终端/命令行所在的目录(外部配置的核心路径,比如jar包放在/opt/app/,./就是/opt/app/)。
核心加载位置(6个,分内置/外部)
第一类:内置配置(classpath下,3个,开发时用)
全部在项目src/main/resources下,打包进jar,开发环境用,生产环境一般不修改内置配置:
classpath:/→src/main/resources/(类路径根目录,最常用,我们之前的配置都放在这)classpath:/config/→src/main/resources/config/(类路径下的config子目录)classpath:/config/*/→src/main/resources/config/子文件夹/(极少用,适合复杂项目的子模块配置)
第二类:外部配置(./下,3个,生产时用)
全部在jar包所在的服务器目录,不打包进jar,生产环境优先用,修改后重启项目即可生效,不用重新打包:
./→ jar包所在的当前目录根目录(比如jar在/opt/app/,就是/opt/app/)./config/→ jar包所在目录的config子目录(生产最推荐,比如/opt/app/config/,规范)./config/*/→ jar包所在目录config的子文件夹(极少用)
可视化位置示例(生产环境jar包部署)
假设jar包放在服务器的/opt/app/目录,外部配置的核心位置就是:
/opt/app/ ├── springboot-profile-demo.jar # 项目jar包 ├── application.yml # 外部配置:当前目录根目录 └── config/ # 外部配置:当前目录config子目录(生产推荐) ├── application.yml ├── application-dev.yml └── application-prod.yml四、重中之重:配置的加载顺序&优先级规则
这是最容易混淆的点,也是生产环境排错的关键,核心原则只有一个:后加载的配置会覆盖先加载的配置(同个配置项,后加载的生效)。
所有优先级规则都围绕「位置优先级」和「profile优先级」两个维度展开,我会先讲通用优先级规则(所有场景都适用),再讲具体的加载顺序(结合位置+profile),最后用通俗示例讲透,保证一看就懂。
规则1:位置优先级(外部 > 内置,config目录 > 根目录)
SpringBoot加载配置时,外部配置的优先级高于内置配置,同级别下,config子目录的优先级高于根目录,这是最核心的位置规则,生产环境就是靠这个规则让「外部配置覆盖jar包内的内置配置」。
官方核心位置优先级排序(从高到低,后加载=高优先级):
外部./config/ > 外部./ > 内置classpath:/config/ > 内置classpath:/通俗解读:
- 服务器上
jar包所在目录/config/的配置(最高优先级,生产最推荐); - 服务器上
jar包所在目录/的配置; - jar包内
classpath:/config/的配置; - jar包内
classpath:/的配置(最低优先级,开发时的默认位置)。
规则2:profile优先级(激活的profile > 全局公共配置,多个激活后覆盖前)
在同一个位置下,配置的加载顺序为:
全局公共配置(application.yml) → 激活的profile配置(application-{active}.yml)核心结论:激活的环境配置会覆盖全局公共配置中的同项配置,公共配置中独有的项会保留(相当于「合并+覆盖」)。
示例:
全局配置application.yml定义了spring.application.name=demo,开发配置application-dev.yml定义了server.port=8080,激活dev后,最终生效的配置是:name=demo(公共)+port=8080(dev);
如果dev配置中也定义了spring.application.name=dev-demo,则最终name=dev-demo(dev覆盖公共)。
补充:如果同时激活多个profile(比如--spring.profiles.active=base,prod),加载顺序是base → prod,后面的prod会覆盖前面的base中的同项配置。
规则3:配置来源优先级(命令行参数 > 配置文件,所有配置之上)
除了配置文件,SpringBoot还能从命令行参数、JVM参数、系统环境变量中读取配置,这些非配置文件的配置来源,优先级高于所有配置文件,这是生产中动态覆盖配置的关键。
所有配置来源的终极优先级排序(从高到低,日常开发/生产只用核心的):
命令行参数(--key=value) > JVM参数(-Dkey=value) > 系统环境变量 > 外部配置文件 > 内置配置文件通俗解读:哪怕你在外部配置文件中写了server.port=80,只要启动时加命令行参数--server.port=9090,最终端口就是9090(命令行最高优先级)。
规则4:配置项的「合并&覆盖」原则(核心)
不同配置文件中的不同配置项,SpringBoot会自动合并,全部生效;相同配置项,会按照「优先级高低」保留最高优先级的那个,这就是「合并+覆盖」,比如:
- 公共配置:A=1,B=2;
- dev配置:B=3,C=4;
- 激活dev后,最终:A=1(公共),B=3(dev覆盖),C=4(dev)。
综合加载顺序&优先级(实战版,必看)
结合「位置+profile+配置来源」,SpringBoot启动时的完整加载顺序(从低到高,后加载覆盖前):
- 内置classpath:/ 的application.yml(公共);
- 内置classpath:/ 的application-{profile}.yml(激活的环境);
- 内置classpath:/config/ 的application.yml(公共);
- 内置classpath:/config/ 的application-{profile}.yml(激活的环境);
- 外部./ 的application.yml(公共);
- 外部./ 的application-{profile}.yml(激活的环境);
- 外部./config/ 的application.yml(公共);
- 外部./config/ 的application-{profile}.yml(激活的环境,配置文件中最高优先级);
- 系统环境变量;
- JVM参数(-D);
- 命令行参数(–,所有配置中最高优先级)。
通俗示例:验证优先级(一看就懂)
假设我们做以下配置,启动命令为:java -jar demo.jar --spring.profiles.active=prod --server.port=9090
- 内置classpath:/application-prod.yml:
server.port=80; - 外部./config/application-prod.yml:
server.port=8888; - 命令行参数:
--server.port=9090。
最终生效端口:9090(命令行最高优先级);
如果去掉命令行参数,生效端口:8888(外部config的prod配置,配置文件最高);
如果再删掉外部config的配置,生效端口:80(内置prod配置)。
五、生产核心:外部配置文件的高级用法
生产环境中,外部配置文件是重中之重,因为它「无需打包、方便修改、权限可控」,除了用SpringBoot默认的外部加载位置,还可以手动指定外部配置文件的路径(适合配置文件不在jar包所在目录的场景,比如统一放在/etc/config/目录)。
SpringBoot提供两个核心参数来手动指定外部配置路径,生产中最常用,必须分清两者的区别:--spring.config.location和--spring.config.additional-location。
1. 追加外部配置路径:--spring.config.additional-location(推荐!)
作用:在SpringBoot默认加载位置的基础上,追加自定义的外部配置路径,自定义路径的优先级高于默认的外部路径,但低于命令行参数。
核心优势:保留默认加载规则,同时增加自定义路径,不会覆盖默认,容错性高,生产首选。
用法:指定配置文件所在的目录(最后加/),支持多个路径(逗号分隔),SpringBoot会自动扫描该目录下的application.yml和application-{profile}.yml:
# 追加单个外部路径:/etc/config/java -jar demo.jar --spring.profiles.active=prod --spring.config.additional-location=/etc/config/# 追加多个外部路径:/etc/config/ 和 /opt/app/config/(逗号分隔,前面的优先级更高)java -jar demo.jar --spring.profiles.active=prod --spring.config.additional-location=/etc/config/,/opt/app/config/2. 覆盖默认配置路径:--spring.config.location(慎用)
作用:完全覆盖SpringBoot的所有默认加载位置,只加载你指定的自定义路径中的配置,默认的内置/外部路径都会失效。
缺点:容错性低,如果指定的路径中没有配置文件,项目会启动失败(因为默认路径被覆盖了),非特殊场景不推荐使用。
用法:和additional-location一致,指定目录(加/):
# 只加载/etc/config/下的配置,默认位置全部失效java -jar demo.jar --spring.profiles.active=prod --spring.config.location=/etc/config/生产最佳实践:外部配置的目录规范
建议将所有外部配置统一放在服务器的专用配置目录,比如/etc/{项目名}/config/,然后用additional-location追加路径,示例:
# 生产启动命令(规范写法)java -jar /opt/app/demo.jar\--spring.profiles.active=prod\--spring.config.additional-location=/etc/demo/config/\--server.tomcat.uri-encoding=UTF-8这样做的好处:
- 配置和程序分离,方便运维管理;
- 可通过Linux权限控制配置文件(比如只有root能修改),提高安全性;
- 项目升级时,只需替换jar包,配置文件无需改动。
六、开发/生产中的避坑指南(高频踩雷点)
- yml多文档块的
---必须顶格:yml的分隔符---不能有任何缩进,否则SpringBoot识别不到多环境,会报错; - profile命名不能错:必须是
application-{profile}.yml,少了-或者拼错(比如applicationdev.yml),SpringBoot无法识别; - 外部配置的路径要加
/:用location/additional-location指定路径时,必须是目录且最后加/(比如/etc/config/),如果写文件路径(比如/etc/config/application.yml),会导致profile配置无法加载; - 命令行参数的
--不能少:启动时的动态参数必须以--开头(比如--server.port=9090),少了会被当成普通参数,SpringBoot无法识别; - 多个profile激活的覆盖顺序:
--spring.profiles.active=base,prod是base先加载,prod后加载,prod覆盖base,不要搞反; - properties和yml共存的优先级:如果项目中同时有
application.properties和application.yml,properties的优先级高于yml(SpringBoot对properties的兼容性更好),建议项目中只选一种格式,避免混乱。
七、总结
- profile核心:是SpringBoot的「环境标签」,配置文件命名必须遵守
application-{profile}.yml/properties,application.yml是全局公共配置; - profile激活:开发用配置文件内
spring.profiles.active,生产必须用命令行参数(--spring.profiles.active=prod),实现包复用; - 加载位置:分内置(
classpath://classpath:/config/,开发用)和外部(.//./config/,生产用),生产推荐jar包所在目录/config/; - 核心优先级:命令行参数 > 外部配置 > 内置配置,config目录 > 根目录,激活的profile > 公共配置,后加载的配置覆盖先加载的;
- 外部配置高级用法:生产用
--spring.config.additional-location追加自定义配置路径(推荐),避免用location覆盖默认; - 核心原则:所有配置的最终生效规则是「合并+覆盖」,不同项合并,相同项按优先级保留最高的。