Maven 的 Profile 是什么?怎么做多环境(dev/test/prod)配置切换?
简化版
**Maven Profile(构建剖面)是一套「可以按条件激活的构建配置」,用来在不同环境/场景下用不同的构建行为(不同的依赖、属性、插件配置、资源文件),最典型的用途是「多环境(dev/test/prod)打包」——同一份代码,打 dev 包用 dev 的配置、打 prod 包用 prod 的配置。**核心机制:① 在 pom.xml(或 settings.xml)里定义多个 <profile>,每个 profile 有 <id> 和一套配置(<properties> 属性、<dependencies> 依赖、<build> 插件/资源等);② 激活方式——手动 mvn package -P prod(-P 指定 profile id),或自动激活(<activation> 按 JDK 版本、OS、属性、文件存在等条件,或 activeByDefault 默认激活);③ 常配合「资源过滤(filtering)」:profile 里定义属性(如 <env>prod</env>)+ 资源文件里用占位符(${env} 或 @env@),构建时 Maven 把占位符替换成 profile 的属性值,从而生成对应环境的配置文件。注意:Spring Boot 项目现在更常用 Spring 自己的 Profile(application-dev.yml + spring.profiles.active,运行时切换),比 Maven Profile(构建时切换、要重新打包)更灵活;两者可结合(Maven Profile 决定打包时激活哪个 Spring Profile)。核心记忆:Maven Profile = 按条件激活的构建配置,-P 指定,常用于多环境打包(构建时切换,配合资源过滤)。
详细版
Maven Profile 的定义和激活:
<profiles>
<!-- dev 环境(默认激活)-->
<profile>
<id>dev</id>
<activation>
<activeByDefault>true</activeByDefault> <!-- 默认激活 -->
</activation>
<properties>
<env>dev</env>
<db.url>jdbc:mysql://localhost:3306/dev</db.url>
</properties>
</profile>
<!-- prod 环境 -->
<profile>
<id>prod</id>
<properties>
<env>prod</env>
<db.url>jdbc:mysql://prod-host:3306/app</db.url>
</properties>
</profile>
</profiles>
<!-- 配合资源过滤:占位符会被 profile 属性替换 -->
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering> <!-- 开启过滤(替换 ${...})-->
</resource>
</resources>
</build>
# application.properties 里用占位符
spring.profiles.active=@env@
# 打包时被 profile 的 <env> 替换:dev 包→dev,prod 包→prod
| 激活方式 | 写法 | 说明 |
|---|---|---|
| 命令行 -P | mvn package -P prod | 手动指定 profile id |
| activeByDefault | <activeByDefault>true | 默认激活(无 -P 时) |
| 按属性 | <activation><property> | 某属性存在/等于某值时激活 |
| 按 JDK | <activation><jdk>17</jdk> | JDK 版本匹配时激活 |
| 按 OS | <activation><os> | 操作系统匹配时激活 |
| 按文件 | <activation><file> | 某文件存在/不存在时激活 |
| settings.xml | <activeProfiles> | 全局激活 |
⚠️ Maven Profile 是「构建时(打包时)」切换配置,而 Spring Boot 的 Profile 是「运行时」切换——这是两个不同层面的东西,别混淆。Maven Profile 在
mvn package时生效,决定「打出来的包里是什么配置」——它的问题是「切环境要重新打包」(打 prod 包和 dev 包是两个不同的产物)。Spring Boot Profile(application-{profile}.yml+spring.profiles.active)是运行时生效——同一个包,启动时用--spring.profiles.active=prod就切到 prod,不用重新打包,更灵活。现代实践通常是:一个包内放所有环境的配置(application-dev.yml、application-prod.yml),运行时用 Spring Profile 切换(-Dspring.profiles.active=prod);Maven Profile 用于「构建层面的差异」(如某环境要不要打进某个依赖、要不要跳过某步)。两者也能结合:Maven Profileprod激活时,通过资源过滤把application.yml里的spring.profiles.active=@profileActive@填成prod。
完整版教学
一、Profile 是什么
先理解 Profile——按条件激活的构建配置:
Maven Profile(构建剖面):
一套"可以按条件激活的构建配置"
→ 不同环境/场景用不同的构建行为
一个 profile 可以包含:
① <properties>:属性(不同环境不同值,如数据库 URL)
② <dependencies>:依赖(某环境才要的依赖)
③ <build>:插件配置、资源过滤(不同环境不同打包行为)
④ <repositories>:仓库
→ 几乎构建的各方面都能按 profile 差异化
最典型用途——多环境打包:
同一份代码,打不同环境的包:
mvn package -P dev → dev 配置的包
mvn package -P prod → prod 配置的包
→ 环境差异(数据库地址、日志级别等)由 profile 提供
为什么需要 Profile:
① 同一份代码要部署到多环境(dev/test/prod)
→ 配置不同(数据库、地址、开关)
② 不同场景要不同构建行为
→ 如某环境跳过测试、某环境打额外依赖
所以 Profile=按条件激活的构建配置,典型用于多环境打包
Maven Profile(构建剖面) 是「按条件激活的构建配置」——不同环境/场景用不同的构建行为。一个 profile 可包含:<properties> 属性、<dependencies> 依赖、<build> 插件/资源过滤、<repositories> 仓库(构建各方面都能差异化)。最典型用途——多环境打包:同一份代码 mvn package -P dev/prod 打不同环境的包。为什么需要:① 同一份代码部署多环境配置不同、② 不同场景要不同构建行为(跳过测试/打额外依赖)。理解「Profile 是按条件激活的构建配置;可含 properties/dependencies/build/repositories;典型用途多环境打包(mvn package -P dev/prod);为什么:同代码部署多环境配置不同+不同场景不同构建行为」,就理解了 Profile 是什么。
二、定义 Profile
理解怎么定义 Profile:
定义 Profile(在 pom.xml 的 <profiles> 里):
<profiles>
<profile>
<id>prod</id> ← profile 的标识(-P prod 用它)
<properties>...</properties> ← 这个 profile 的属性
<dependencies>...</dependencies>
<build>...</build>
</profile>
</profiles>
多环境的典型定义:
<profile><id>dev</id>
<properties><env>dev</env>
<db.url>jdbc:mysql://localhost/dev</db.url></properties>
</profile>
<profile><id>prod</id>
<properties><env>prod</env>
<db.url>jdbc:mysql://prod-host/app</db.url></properties>
</profile>
→ 每个环境一个 profile,属性不同
定义位置:
① pom.xml 的 <profiles>:项目级(跟着项目走)
② settings.xml 的 <profiles>:用户/全局级
(如私服地址、本机特定配置,不该进版本控制的)
所以定义 Profile:在<profiles>里,每个 profile 有 id+一套配置
定义 Profile(在 <profiles> 里):每个 <profile> 有 <id>(标识,-P 用它)+ 一套配置(<properties>/<dependencies>/<build>)。多环境典型定义:每个环境一个 profile(dev/prod),属性不同(如 db.url)。定义位置:① pom.xml 的 <profiles>(项目级、跟项目走)、② settings.xml 的 <profiles>(用户/全局级,如私服地址、不该进版本控制的)。理解「定义 Profile 在
三、激活 Profile
理解 Profile 的激活方式:
激活方式:
① 命令行 -P(手动,最常用):
mvn package -P prod
mvn package -P prod,extra(多个)
→ 明确指定激活哪个 profile
② activeByDefault(默认激活):
<activation><activeByDefault>true</activeByDefault></activation>
→ 没有 -P 指定时激活
注意:只要有任何 -P 或其他方式激活了别的 profile,
activeByDefault 就失效(易错点)
③ 按属性激活:
<activation><property>
<name>env</name><value>prod</value>
</property></activation>
→ mvn package -Denv=prod 时激活
④ 按 JDK 版本:<activation><jdk>17</jdk></activation>
⑤ 按 OS:<activation><os><family>windows</family></os></activation>
⑥ 按文件存在:<activation><file><exists>xxx</exists></file></activation>
⑦ settings.xml 全局激活:
<activeProfiles><activeProfile>prod</activeProfile></activeProfiles>
查看激活了哪些:
mvn help:active-profiles
所以激活:-P(手动最常用)/activeByDefault/按属性·JDK·OS·文件/settings.xml
Profile 激活方式:① 命令行 -P(手动最常用,mvn package -P prod)、② activeByDefault(默认激活,没 -P 时激活;注意有任何其他激活时就失效——易错点)、③ 按属性(<property> name/value,-Denv=prod 时激活)、④ 按 JDK(<jdk>)、⑤ 按 OS、⑥ 按文件存在、⑦ settings.xml 全局激活(<activeProfiles>)。查看:mvn help:active-profiles。理解「激活:-P(手动最常用)/activeByDefault(默认,有其他激活时失效)/按属性(-Denv=prod)/按 JDK·OS·文件/settings.xml 全局;查看 mvn help:active-profiles」,就掌握了激活 Profile。
四、配合资源过滤做多环境
理解 Profile 配合资源过滤——多环境配置的核心手法:
资源过滤(filtering)+ Profile = 多环境配置:
步骤:
① Profile 里定义属性(不同环境不同值):
<profile><id>prod</id>
<properties><db.url>jdbc:mysql://prod/app</db.url></properties>
</profile>
② 开启资源过滤(<build>里):
<resources><resource>
<directory>src/main/resources</directory>
<filtering>true</filtering> ← 开启(替换占位符)
</resource></resources>
③ 资源文件用占位符:
application.properties:
db.url=${db.url} ← ${...} 占位符
(Spring Boot 里推荐用 @db.url@ 避免和 Spring 的 ${} 冲突)
④ 打包时:Maven 把占位符替换成激活 profile 的属性值
mvn package -P prod
→ application.properties 里 ${db.url} 变成 prod 的值
效果:
同一份 application.properties 模板
→ 不同 profile 打包,占位符填不同的值
→ 生成对应环境的配置
Spring Boot 的 @...@ 占位符:
Spring Boot 父 POM 把资源过滤的占位符改成 @...@
(因为 Spring 自己用 ${...},避免冲突)
→ Spring Boot 项目用 @env@ 而不是 ${env}
所以资源过滤+Profile:属性+占位符,打包时替换,生成对应环境配置
资源过滤(filtering)+ Profile = 多环境配置的核心手法:① Profile 里定义属性(不同环境不同值)、② 开启资源过滤(<filtering>true</filtering>)、③ 资源文件用占位符(${db.url},Spring Boot 推荐 @db.url@ 避免和 Spring 的 ${} 冲突)、④ 打包时 Maven 把占位符替换成激活 profile 的属性值。效果:同一份配置模板、不同 profile 打包占位符填不同值、生成对应环境配置。Spring Boot 用 @...@ 占位符(因 Spring 自己用 ${}、避免冲突)。理解「资源过滤+Profile:①Profile 定义属性②开启 filtering③资源文件占位符(${…}或 Spring Boot 的@…@)④打包时替换成 profile 属性值;同一模板不同 profile 生成不同环境配置;Spring Boot 用@…@避免和 Spring ${} 冲突」,就掌握了资源过滤做多环境。
五、Maven Profile vs Spring Boot Profile
理解两种 Profile 的区别——高频易混:
Maven Profile vs Spring Boot Profile(两个层面):
Maven Profile(构建时):
在 mvn package 时生效
→ 决定"打出来的包里是什么配置/依赖/构建行为"
切环境 = 重新打包(-P prod 打 prod 包)
问题:dev 包和 prod 包是两个不同的产物
Spring Boot Profile(运行时):
application-{profile}.yml + spring.profiles.active
在应用"启动时"生效
→ 同一个包,启动时 --spring.profiles.active=prod 切到 prod
优势:一个包跑所有环境,运行时切换,不用重新打包
对比:
维度 Maven Profile Spring Boot Profile
生效时机 构建/打包时 运行时(启动)
切换 重新打包 改启动参数(同一个包)
管什么 依赖/构建/资源 应用配置(yml)
灵活性 低(要重新打包) 高(一个包切环境)
现代实践(推荐):
① 应用配置用 Spring Boot Profile(一个包放所有环境 yml,运行时切)
→ 一次构建,到处运行(不用为每个环境打包)
② Maven Profile 用于"构建层面差异"
(某环境要不要某依赖、要不要跳某步骤)
两者结合:
Maven Profile 决定打包时激活哪个 Spring Profile:
application.yml: spring.profiles.active=@profileActive@
Maven profile prod: <profileActive>prod</profileActive>
→ mvn package -P prod 打的包默认用 prod Spring Profile
所以 Maven Profile 构建时(重新打包)、Spring Profile 运行时(一个包切换)
Maven Profile vs Spring Boot Profile(两个层面、高频易混):Maven Profile 构建时生效(mvn package 时、决定打出来的包里是什么、切环境要重新打包);Spring Boot Profile 运行时生效(application-{profile}.yml + spring.profiles.active、启动时切换、一个包跑所有环境不用重新打包)。对比:Maven 构建时/重新打包/管依赖构建资源、Spring Boot 运行时/改启动参数/管应用配置。现代实践:应用配置用 Spring Boot Profile(一次构建到处运行)、Maven Profile 用于构建层面差异。两者结合:Maven Profile 决定打包时激活哪个 Spring Profile(spring.profiles.active=@profileActive@)。理解「Maven Profile 构建时(打包时生效,切环境重新打包,管依赖构建资源)、Spring Boot Profile 运行时(启动时生效,一个包切环境,管应用配置);现代实践应用配置用 Spring Boot Profile(一次构建到处运行)、Maven Profile 管构建差异;结合 Maven 决定打包时激活哪个 Spring Profile」,就掌握了两种 Profile 的区别。
六、实践与总结
总结 Maven Profile 的实践:
实践建议:
① 应用配置(数据库、地址等)优先用 Spring Boot Profile
(运行时切换,一次构建到处运行,别为每个环境打包)
② Maven Profile 用于"构建层面"的差异:
- 某环境要不要打进某依赖
- 某环境要不要跳过某步骤(测试、混淆)
- 私服/仓库配置(settings.xml 的 profile)
③ 资源过滤慎用(Spring Boot 用 @...@ 避免和 ${} 冲突)
④ 注意 activeByDefault 的坑(有其他激活时它失效)
常见用途:
① 多环境(结合资源过滤或 Spring Profile)
② 私服/仓库配置(settings.xml)
③ 条件依赖(某 JDK/OS 才要的依赖)
④ 发布 profile(release 时才做的额外步骤,如签名、源码 jar)
核心总结:
Maven Profile=按条件激活的构建配置
激活:-P(手动)/activeByDefault/按属性·JDK·OS·文件/settings.xml
多环境:Profile 属性+资源过滤占位符,打包时替换
vs Spring Boot Profile:Maven 构建时(重新打包)、Spring 运行时(一个包)
现代实践:应用配置用 Spring Profile、Maven Profile 管构建差异
Maven Profile 实践建议:① 应用配置优先用 Spring Boot Profile(运行时切换、一次构建到处运行)、② Maven Profile 用于构建层面差异(某环境的依赖/跳过步骤/私服配置)、③ 资源过滤慎用(Spring Boot 用 @...@)、④ 注意 activeByDefault 的坑。常见用途:多环境、私服/仓库配置、条件依赖、发布 profile(release 才做的签名/源码 jar)。理解「实践:应用配置用 Spring Profile、Maven Profile 管构建差异(依赖/跳步骤/私服);资源过滤慎用(Spring Boot @…@);注意 activeByDefault 坑;用途多环境/私服/条件依赖/发布 profile」,就掌握了实践与总结。
记忆钩子:「Maven Profile(构建剖面)=按条件激活的构建配置,不同环境/场景用不同构建行为(依赖/属性/插件/资源),典型用于多环境打包;定义在
里,每个 profile 有 id+一套配置;激活方式:①命令行 -P prod(手动最常用)②activeByDefault(默认激活,有其他激活时失效-易错)③按属性(-Denv=prod)④按 JDK/OS/文件⑤settings.xml 全局;多环境核心手法=Profile 属性+资源过滤(filtering)占位符,打包时 Maven 把${db.url}(Spring Boot 用@db.url@避免和 Spring ${}冲突)替换成 profile 属性值;★Maven Profile 构建时(打包时切换,重新打包)vs Spring Boot Profile 运行时(application-{profile}.yml+spring.profiles.active,一个包启动时切换,更灵活);现代实践:应用配置用 Spring Profile(一次构建到处运行)、Maven Profile 管构建层面差异」 。
七、常见误区与追问
- 误区:Maven Profile 和 Spring Boot Profile 是一回事。 是两个不同层面的东西:Maven Profile 在「构建时(mvn package)」生效,决定打出来的包里是什么配置/依赖/构建行为,切换环境要重新打包;Spring Boot Profile(application-{profile}.yml + spring.profiles.active)在「运行时(启动)」生效,同一个包用启动参数 —spring.profiles.active=prod 就切到 prod,不用重新打包,更灵活。
- 误区:activeByDefault 的 profile 一定会激活。 不一定——activeByDefault 只在「没有任何其他 profile 被激活」时生效;一旦你用 -P 激活了别的 profile,或有 profile 通过 activation 条件被激活,activeByDefault 的那个就会失效(不再默认激活);这是常见的坑,想让 dev 默认激活但用 -P prod 后 dev 就不激活了。
- 误区:多环境配置只能用 Maven Profile 的资源过滤。 现代 Spring Boot 项目更推荐用 Spring Boot Profile(一个包内放 application-dev.yml、application-prod.yml,运行时用 spring.profiles.active 切换),实现「一次构建、到处运行」,比 Maven Profile(要为每个环境重新打包)更符合云原生/容器化的实践;Maven Profile 的资源过滤更适合构建层面的差异。
- 误区:Spring Boot 项目资源过滤也用 ${…} 占位符。 Spring Boot 父 POM 特意把资源过滤的占位符从 ${…} 改成了 @…@——因为 Spring 自己用 ${…} 做属性解析,如果 Maven 也用 ${…} 过滤会冲突(Maven 可能提前把 Spring 的 ${} 占位符也替换掉);所以 Spring Boot 项目里资源过滤要用 @env@ 而不是 ${env}。
- 追问:Maven Profile 怎么做多环境配置切换? 核心手法是「Profile 属性 + 资源过滤」:① 为每个环境定义一个 profile(dev/test/prod),每个 profile 的
里放该环境的值(如 db.url、日志级别);② 在 里对资源目录开启 filtering( true );③ 资源文件(application.properties)里用占位符 ${db.url}(Spring Boot 用 @db.url@);④ 打包时 mvn package -P prod,Maven 会把占位符替换成 prod profile 的属性值,生成 prod 环境的配置文件;这样同一份模板、不同 profile 打包就得到不同环境的配置。 - 追问:Maven Profile 有哪些激活方式? ① 命令行 -P:mvn package -P prod(手动指定,最常用,可逗号分隔多个);② activeByDefault:
true ,没有其他激活时默认激活;③ 按属性:env prod ,当 -Denv=prod 时激活;④ 按 JDK 版本:17 ;⑤ 按 OS:;⑥ 按文件存在/不存在: / ;⑦ 在 settings.xml 里用 全局激活;用 mvn help:active-profiles 查看当前激活了哪些。 - 追问:现代 Spring Boot 项目该用 Maven Profile 还是 Spring Boot Profile 做多环境? 推荐以 Spring Boot Profile 为主:把所有环境的配置(application-dev.yml、application-prod.yml)都打进一个包,运行时用 -Dspring.profiles.active=prod(或环境变量 SPRING_PROFILES_ACTIVE)切换,实现「一次构建、到处运行」,特别适合容器化部署(同一个镜像跑所有环境);Maven Profile 保留给「构建层面的真正差异」——如某环境才需要的依赖、release 时才做的签名/源码 jar;两者可结合:用 Maven Profile 通过资源过滤把 application.yml 里的 spring.profiles.active=@profileActive@ 填成默认激活的 Spring Profile。
八、加强记忆
Maven Profile(构建剖面)是「按条件激活的构建配置」——在不同环境/场景下用不同的构建行为(依赖、属性、插件配置、资源文件),最典型用途是多环境(dev/test/prod)打包。定义:在 <profiles> 里,每个 <profile> 有 <id> + 一套配置。激活方式:① 命令行 -P prod(手动最常用)、② activeByDefault(默认激活,但有其他激活时失效——易错点)、③ 按属性(-Denv=prod)、④ 按 JDK/OS/文件、⑤ settings.xml 全局激活。多环境核心手法 = Profile 属性 + 资源过滤(filtering)占位符:profile 里定义属性 + 资源文件用占位符(${db.url},Spring Boot 用 @db.url@ 避免和 Spring 的 ${} 冲突),打包时 Maven 把占位符替换成激活 profile 的属性值。关键区分:Maven Profile 是「构建时(打包时)」切换(要重新打包),Spring Boot Profile(application-{profile}.yml + spring.profiles.active)是「运行时」切换(一个包启动时切换,更灵活);现代实践以 Spring Boot Profile 为主(一次构建、到处运行、适合容器化),Maven Profile 管构建层面差异,两者可结合。一句话「Maven Profile=按条件激活的构建配置(用于多环境打包),-P prod 手动激活/activeByDefault 默认(有其他激活时失效);多环境靠 Profile 属性+资源过滤占位符(打包时替换,Spring Boot 用@…@);Maven Profile 构建时切换(重新打包)、Spring Boot Profile 运行时切换(一个包更灵活),现代以 Spring Profile 为主」。