Maven Profile 与多环境构建实战
同一套代码要构建出开发/测试/生产不同配置的产物,靠的是 Profile + 资源过滤。Profile 控制"构建时用哪套属性",资源过滤负责把占位符替换为对应值。
Profile 是什么
Profile 是一组可条件激活的配置,激活后其属性、依赖、插件会合并进有效 POM:
Profile = 一组配置(properties / dependencies / plugins / repositories ...)
+ 激活条件(命令、JDK、属性、文件、默认)未激活的 Profile 不生效;多个 Profile 同时激活时配置合并。
Profile 声明位置
| 位置 | 作用域 | 使用场景 |
|---|---|---|
| pom.xml | 当前项目 | 多环境构建 |
| settings.xml | 全局/用户 | 仓库、镜像、全局属性 |
| 父 POM | 继承给子模块 | 团队统一配置 |
xml
<profiles>
<profile>
<id>dev</id>
<properties>
<env>dev</env>
<server.port>8080</server.port>
<db.url>jdbc:mysql://localhost:3306/dev_db</db.url>
</properties>
</profile>
<profile>
<id>prod</id>
<properties>
<env>prod</env>
<server.port>8080</server.port>
<db.url>jdbc:mysql://10.0.0.1:3306/prod_db</db.url>
</properties>
</profile>
</profiles>激活方式
1. 命令行激活(最常用)
bash
mvn clean package -P prod
mvn clean package -P dev,test # 同时激活多个
mvn clean package -P !dev # 排除某 Profile2. 默认激活
xml
<profile>
<id>dev</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
</profile>任何 Profile 被显式激活(如 -P prod)时,默认激活的 Profile 自动失效。
3. 按 JDK 版本激活
xml
<activation>
<jdk>17</jdk> <!-- 精确匹配 -->
</activation>
<activation>
<jdk>[17,)</jdk> <!-- 版本范围:17 及以上 -->
</activation>4. 按系统属性激活
xml
<activation>
<property>
<name>env</name>
<value>prod</value> <!-- -Denv=prod 时激活 -->
</property>
</activation>5. 按文件存在激活
xml
<activation>
<file>
<exists>config/prod.properties</exists>
<missing>config/dev.properties</missing>
</file>
</activation>激活方式优先级
命令行 -P > 系统属性 > JDK > 文件 > activeByDefault资源过滤:多环境配置替换
Profile 提供属性,资源过滤把资源文件中的占位符替换成属性值,实现"一套模板,多套产物"。
1. 开启资源过滤
xml
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
</build>2. 模板中使用占位符
properties
# src/main/resources/application.properties
spring.profiles.active=@env@
server.port=@server.port@
spring.datasource.url=@db.url@占位符默认是 @name@(可通过 <delimiter> 配置改为 ${name})。
3. 按环境构建
bash
mvn clean package -P dev # @env@ → dev,@db.url@ → 开发库
mvn clean package -P prod # @env@ → prod,@db.url@ → 生产库常见坑:过滤了不该过滤的文件
配置文件中有 ${...} 时可能被误替换,用 <excludes> 排除或设置 <filtering>false</filtering>:
xml
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
<excludes>
<exclude>application-dev.properties</exclude>
<exclude>application-prod.properties</exclude>
</excludes>
</resource>模块级 Profile
多模块项目可以在父 POM 定义 Profile,控制不同构建场景包含的模块:
xml
<profile>
<id>full</id>
<modules>
<module>common</module>
<module>service</module>
<module>web</module>
<module>admin</module>
<module>batch</module>
</modules>
</profile>
<profile>
<id>minimal</id>
<modules>
<module>common</module>
<module>web</module>
</modules>
</profile>bash
mvn clean install -P minimal # 只构建 common + web子模块也可以声明自己的 Profile:父 POM 的 Profile 激活时,子模块同名 Profile 一起激活(可结合 <module> 属性如 ${project.artifactId} 控制)。
Spring Boot 多环境打包实战
结合 Spring Boot,用 profile 控制最终产物名与配置:
xml
<build>
<finalName>${project.artifactId}-${env}</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals><goal>repackage</goal></goals>
</execution>
</executions>
</plugin>
</plugins>
</build>bash
mvn clean package -P dev # → target/my-app-dev.jar
mvn clean package -P prod # → target/my-app-prod.jar常见问题
- Profile 没生效? 检查 id 是否写错、
activeByDefault是否被其他显式激活覆盖、mvn help:active-profiles查看当前激活列表。 - 占位符没被替换? 确认资源
<filtering>true</filtering>已配置,且占位符写法(@name@)与 delimiter 一致。 - 打包产物区分不明显? 用
<finalName>拼上-${env},产物名直观区分环境。 - Profile 之间互相影响? 多个 Profile 激活时属性按声明顺序合并,同名属性后声明覆盖先声明,尽量避免同名冲突。