Maven Profile 多环境配置:如何实现一套代码适配 dev/test/prod?(附完整配置)

举报
行者·全栈架构师 发表于 2026/05/23 15:07:37 2026/05/23
【摘要】 开发时改配置、测试时改配置、上线时还要改配置——有没有一种方法能让代码在不同环境自动适配?本文介绍 Maven Profile 的用法,从基础的 pom.xml 配置到生产环境的敏感信息管理,手把手教你实现一套代码多环境运行。

Maven Profile 多环境配置:如何实现一套代码适配 dev/test/prod?(附完整配置)

⏱️ 阅读预估时间: 12 分钟

摘要: 开发时改配置、测试时改配置、上线时还要改配置——有没有一种方法能让代码在不同环境自动适配?本文介绍 Maven Profile 的用法,从基础的 pom.xml 配置到生产环境的敏感信息管理,手把手教你实现一套代码多环境运行。

🎯 前言:多环境管理的痛点

1.1 那些年被环境配置坑过的经历

场景一:手动改配置上线
开发:代码写完了,准备上线
运维:好的,我先改下数据库配置
再改 Redis 地址
还有消息队列...
哎呀,改错了一个参数!
结果:上线失败,回滚...

场景二:配置文件满天飞
config-dev.properties
config-test.properties
config-prod.properties
config-backup.properties
config-old.properties
...
哪个才是真正在用的?

场景三:环境混淆
开发 A: 我本地好好的啊
开发 B:你用的是哪个环境?
开发 A:好像是 test 环境?
开发 B:不对,这是 prod 的配置!
完了,生产数据被污染了...

1.2 为什么需要 Profile?

对比
对比
对比
传统方式
手动修改配置
多套配置文件
容易出错
Maven Profile
自动切换
一套代码
标准化管理

🌟 第一章:Profile 基础入门

2.1 什么是 Profile?

Profile 定义:
Profile 是 Maven 的一组配置集合,可以根据不同条件激活

核心作用:

- 同一套代码,不同环境运行
- 动态切换配置,无需修改代码
- 标准化环境管理

适用场景:开发环境 (development)测试环境 (testing)预发布环境 (staging)生产环境 (production)

2.2 Profile 的三种类型

<!-- 类型 1: pom.xml 中的 Profile -->
<project>
  <profiles>
    <profile>
      <id>dev</id>
      <!-- 配置内容 -->
    </profile>
  </profiles>
</project>

  <!-- 类型 2: settings.xml 中的 Profile -->
<settings>
<profiles>
  <profile>
    <id>global-config</id>
    <!-- 全局配置 -->
  </profile>
</profiles>
</settings>

  <!-- 类型 3: 独立的 profile.xml(较少用) -->

💡 第二章:数据库配置分离实战

3.1 项目结构

my-project/
├── src/
│   ├── main/
│   │   ├── java/
│   │   └── resources/
│   │       ├── application.yml           # 主配置文件
│   │       ├── application-dev.yml       # 开发环境
│   │       ├── application-test.yml      # 测试环境
│   │       └── application-prod.yml      # 生产环境
│   └── test/
├── pom.xml
└── scripts/
    └── deploy.sh

3.2 pom.xml 配置


<project>
  <profiles>
    <!-- 开发环境 -->
    <profile>
      <id>dev</id>
      <properties>
        <!-- 环境标识 -->
        <env.profile>dev</env.profile>

        <!-- 数据库配置 -->
        <db.url>jdbc:mysql://localhost:3306/dev_db?useSSL=false</db.url>
        <db.username>dev_user</db.username>
        <db.password>dev_password</db.password>
        <db.driver-class-name>com.mysql.cj.jdbc.Driver</db.driver-class-name>

        <!-- Redis 配置 -->
        <redis.host>localhost</redis.host>
        <redis.port>6379</redis.port>
        <redis.password></redis.password>

        <!-- 日志级别 -->
        <log.level>DEBUG</log.level>
        <log.pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n</log.pattern>
      </properties>
      <activation>
        <activeByDefault>true</activeByDefault>
      </activation>
    </profile>

    <!-- 测试环境 -->
    <profile>
      <id>test</id>
      <properties>
        <env.profile>test</env.profile>

        <db.url>jdbc:mysql://test-db-server:3306/test_db?useSSL=false</db.url>
        <db.username>test_user</db.username>
        <db.password>test_password</db.password>
        <db.driver-class-name>com.mysql.cj.jdbc.Driver</db.driver-class-name>

        <redis.host>test-redis-server</redis.host>
        <redis.port>6379</redis.port>
        <redis.password>redis_password</redis.password>

        <log.level>INFO</log.level>
        <log.pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n</log.pattern>
      </properties>
    </profile>

    <!-- 生产环境 -->
    <profile>
      <id>prod</id>
      <properties>
        <env.profile>prod</env.profile>

        <db.url>jdbc:mysql://prod-db-master:3306/prod_db?useSSL=true&amp;requireSSL=true</db.url>
        <db.username>${env.PROD_DB_USERNAME}</db.username>
        <db.password>${env.PROD_DB_PASSWORD}</db.password>
        <db.driver-class-name>com.mysql.cj.jdbc.Driver</db.driver-class-name>

        <redis.host>prod-redis-cluster</redis.host>
        <redis.port>6379</redis.port>
        <redis.password>${env.PROD_REDIS_PASSWORD}</redis.password>

        <log.level>WARN</log.level>
        <log.pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</log.pattern>
      </properties>
    </profile>
  </profiles>
</project>

3.3 Spring Boot 集成

# application.yml
spring:
  profiles:
    active: @env.profile@

  datasource:
    url: ${db.url}
    username: ${db.username}
    password: ${db.password}
    driver-class-name: ${db.driver-class-name}

  redis:
    host: ${redis.host}
    port: ${redis.port}
    password: ${redis.password}

logging:
  level:
    root: ${log.level}
  pattern:
    console: ${log.pattern}

3.4 资源文件过滤


<build>
  <resources>
    <resource>
      <directory>src/main/resources</directory>
      <includes>
        <include>**/*.yml</include>
        <include>**/*.properties</include>
        <include>**/*.xml</include>
      </includes>
      <filtering>true</filtering>  <!-- 启用变量替换 -->
    </resource>
  </resources>
</build>

🔐 第三章:敏感信息加密

4.1 环境变量方式(推荐⭐⭐⭐⭐⭐)

<!-- pom.xml -->
<profile>
  <id>prod</id>
  <properties>
    <!-- 从环境变量读取 -->
    <db.username>${env.PROD_DB_USERNAME}</db.username>
    <db.password>${env.PROD_DB_PASSWORD}</db.password>
    <redis.password>${env.PROD_REDIS_PASSWORD}</redis.password>
    <jwt.secret>${env.JWT_SECRET}</jwt.secret>
  </properties>
</profile>

设置环境变量:

# Linux/Mac
export PROD_DB_USERNAME=prod_admin
export PROD_DB_PASSWORD=SecureP@ssw0rd!
export PROD_REDIS_PASSWORD=RedisP@ss!
export JWT_SECRET=MySuperSecretJWTKey123!

# Windows PowerShell
$env:PROD_DB_USERNAME="prod_admin"
$env:PROD_DB_PASSWORD="SecureP@ssw0rd!"

4.2 Maven 密码加密

# 步骤 1: 生成主密码
mvn --encrypt-master-password
# 输入后得到:{QJ6wvuEfacMHmlqomr3c1IdKJ3DyGxpZgFeoZeXkI8Y=}

# 步骤 2: 创建 security-settings.xml
cat > ~/.m2/security-settings.xml << EOF
<settingsSecurity>
  <master>{QJ6wvuEfacMHmlqomr3c1IdKJ3DyGxpZgFeoZeXkI8Y=}</master>
</settingsSecurity>
EOF

chmod 600 ~/.m2/security-settings.xml

# 步骤 3: 加密服务器密码
mvn --encrypt-password
# 输入密码得到:{SmgeP1a3U6iVz7TfQA5QRw==}

# 步骤 4: 在 settings.xml 中使用
<servers>
  <server>
    <id>prod-db</id>
    <username>prod_admin</username>
    <password>{SmgeP1a3U6iVz7TfQA5QRw==}</password>
  </server>
</servers>

🚀 第四章:一键切换环境

5.1 命令行切换

# 方式 1: 使用-P参数
mvn clean package -Pdev
mvn clean package -Ptest
mvn clean package -Pprod

# 方式 2: 设置默认 Profile
# 在 pom.xml 中设置 activeByDefault
<activation>
  <activeByDefault>true</activeByDefault>
</activation>

5.2 自动化部署脚本

#!/bin/bash
# deploy.sh

ENV=${1:-dev}  # 默认为 dev 环境

echo "🚀 开始部署到 $ENV 环境..."

# 1. 清理旧的构建
echo "1. 清理旧构建..."
mvn clean

# 2. 根据环境打包
echo "2. 打包应用 ($ENV 环境)..."
mvn package -P$ENV -DskipTests

# 3. 停止旧服务
echo "3. 停止旧服务..."
sudo systemctl stop myapp

# 4. 备份旧版本
echo "4. 备份旧版本..."
sudo cp /opt/myapp/app.jar /opt/myapp/app.jar.backup.$(date +%Y%m%d_%H%M%S)

# 5. 部署新版本
echo "5. 部署新版本..."
sudo cp target/myapp-1.0.0.jar /opt/myapp/app.jar

# 6. 启动服务
echo "6. 启动服务..."
sudo systemctl start myapp

# 7. 检查状态
echo "7. 检查服务状态..."
sleep 5
sudo systemctl status myapp

echo ""
echo "✅ 部署完成!环境:$ENV"

使用方法:

# 部署到开发环境
./deploy.sh dev

# 部署到测试环境
./deploy.sh test

# 部署到生产环境
./deploy.sh prod

5.3 Docker 集成

# Dockerfile
FROM openjdk:17-slim

WORKDIR /app

# 复制 jar 包
COPY target/myapp-*.jar app.jar

# 环境变量(可在运行时覆盖)
ENV ENV_PROFILE=prod
ENV DB_HOST=localhost
ENV DB_PORT=3306

# 启动命令
ENTRYPOINT ["sh", "-c", "java -jar app.jar --spring.profiles.active=${ENV_PROFILE}"]

运行不同环境:

# 开发环境
docker run -e ENV_PROFILE=dev myapp:latest

# 测试环境
docker run -e ENV_PROFILE=test myapp:latest

# 生产环境(带完整配置)
docker run \
  -e ENV_PROFILE=prod \
  -e DB_HOST=prod-db \
  -e DB_PASSWORD=secret \
  myapp:latest

🏢 第五章:企业级实战案例

案例一:微服务项目多环境管理

项目背景:

- 20+ 个微服务模块
- 4 套环境(dev/test/staging/prod)
- 每个服务都有独立配置
- 需要统一管理和快速切换

解决方案:
使用 Parent POM + Profile 统一管理

Parent POM 配置:

<!-- parent/pom.xml -->
<project>
  <groupId>com.company</groupId>
  <artifactId>parent</artifactId>
  <version>1.0.0</version>
  <packaging>pom</packaging>

  <profiles>
    <profile>
      <id>dev</id>
      <properties>
        <spring.profiles.active>dev</spring.profiles.active>
        <docker.registry>dev-registry.company.com</docker.registry>
        <config.server.uri>http://dev-config:8888</config.server.uri>
      </properties>
    </profile>

    <profile>
      <id>test</id>
      <properties>
        <spring.profiles.active>test</spring.profiles.active>
        <docker.registry>test-registry.company.com</docker.registry>
        <config.server.uri>http://test-config:8888</config.server.uri>
      </properties>
    </profile>

    <profile>
      <id>prod</id>
      <properties>
        <spring.profiles.active>prod</spring.profiles.active>
        <docker.registry>prod-registry.company.com</docker.registry>
        <config.server.uri>http://prod-config:8888</config.server.uri>
      </properties>
    </profile>
  </profiles>

  <build>
    <plugins>
      <!-- Docker 插件统一配置 -->
      <plugin>
        <groupId>com.spotify</groupId>
        <artifactId>docker-maven-plugin</artifactId>
        <configuration>
          <registryUrl>${docker.registry}</registryUrl>
          <imageName>${docker.registry}/${project.name}:${project.version}</imageName>
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>

子模块继承:

<!-- user-service/pom.xml -->
<project>
  <parent>
    <groupId>com.company</groupId>
    <artifactId>parent</artifactId>
    <version>1.0.0</version>
  </parent>

  <!-- 自动继承父 POM 的 Profile -->
</project>

一键构建所有服务:

#!/bin/bash
# build-all.sh

ENV=${1:-dev}

echo "🏗️ 开始构建所有服务 ($ENV 环境)..."

# 构建父 POM
cd parent && mvn clean install -P$ENV

# 构建所有子模块
for module in user-service order-service product-service; do
  echo "构建 $module..."
  cd $module && mvn clean package -P$ENV -DskipTests
done

echo "✅ 所有服务构建完成!"

案例二:CI/CD流水线集成

# .gitlab-ci.yml

stages:
  - build
  - test
  - deploy

variables:
  MAVEN_OPTS: "-XX:MaxMetaspaceSize=512m"

# 构建阶段
build:dev:
  stage: build
  script:
    - mvn clean package -Pdev -DskipTests
  only:
    - develop

build:test:
  stage: build
  script:
    - mvn clean package -Ptest
  only:
    - test

build:prod:
  stage: build
  script:
    - mvn clean package -Pprod -DskipTests
  only:
    - master

# 测试阶段
test:unit:
  stage: test
  script:
    - mvn test -Ptest
  only:
    - test

test:integration:
  stage: test
  script:
    - mvn verify -Ptest -DskipITs=false
  only:
    - test

# 部署阶段
deploy:dev:
  stage: deploy
  script:
    - ./deploy.sh dev
  only:
    - develop

deploy:test:
  stage: deploy
  script:
    - ./deploy.sh test
  only:
    - test
  when: manual  # 手动触发

deploy:prod:
  stage: deploy
  script:
    - ./deploy.sh prod
  only:
    - master
  when: manual  # 手动触发
  environment:
    name: production
    url: https://www.example.com

📊 第六章:最佳实践总结

7.1 Profile 命名规范

推荐命名:
✅ dev / development - 开发环境
✅ test / testing - 测试环境
✅ staging / pre - 预发布环境
✅ prod / production - 生产环境
✅ local - 本地个人环境

不推荐:
❌ environment1, environment2 (无意义)
❌ my-env, test-env (不规范)
❌ dev1, dev2, dev3 (易混淆)

7.2 配置分离原则

应该分离的配置:
✅ 数据库连接
✅ Redis/MQ 等中间件
✅ 第三方 API 密钥
✅ 日志级别
✅ 功能开关
✅ 缓存策略

不应该分离的配置:
❌ 业务逻辑相关
❌ 核心算法参数
❌ 不变的常量

7.3 安全检查清单

上线前必查:
□ 生产环境没有硬编码密码
□ 使用了环境变量或加密配置
□ 数据库连接使用只读账号(查询服务)
□ 开启了 SSL/TLS
□ 日志级别设置为 WARNERROR
□ 关闭了 DEBUG 端点
□ 启用了性能监控
□ 配置了告警通知

🎁 福利:完整配置模板

企业级 pom.xml 模板

<?xml version="1.0" encoding="UTF-8"?>
<project>
  <modelVersion>4.0.0</modelVersion>

  <properties>
    <java.version>17</java.version>
    <maven.compiler.source>17</maven.compiler.source>
    <maven.compiler.target>17</maven.compiler.target>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>

  <profiles>
    <!-- ==================== 开发环境 ==================== -->
    <profile>
      <id>dev</id>
      <properties>
        <env.profile>dev</env.profile>
        <db.url>jdbc:mysql://localhost:3306/dev_db</db.url>
        <db.username>dev</db.username>
        <db.password>dev</db.password>
        <redis.host>localhost</redis.host>
        <log.level>DEBUG</log.level>
      </properties>
      <activation>
        <activeByDefault>true</activeByDefault>
      </activation>
    </profile>

    <!-- ==================== 测试环境 ==================== -->
    <profile>
      <id>test</id>
      <properties>
        <env.profile>test</env.profile>
        <db.url>jdbc:mysql://test-db:3306/test_db</db.url>
        <db.username>test</db.username>
        <db.password>test</db.password>
        <redis.host>test-redis</redis.host>
        <log.level>INFO</log.level>
      </properties>
    </profile>

    <!-- ==================== 生产环境 ==================== -->
    <profile>
      <id>prod</id>
      <properties>
        <env.profile>prod</env.profile>
        <db.url>jdbc:mysql://prod-db:3306/prod_db</db.url>
        <db.username>${env.PROD_DB_USERNAME}</db.username>
        <db.password>${env.PROD_DB_PASSWORD}</db.password>
        <redis.host>prod-redis</redis.host>
        <redis.password>${env.PROD_REDIS_PASSWORD}</redis.password>
        <log.level>WARN</log.level>
      </properties>
    </profile>
  </profiles>

  <build>
    <resources>
      <resource>
        <directory>src/main/resources</directory>
        <filtering>true</filtering>
      </resource>
    </resources>

    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-resources-plugin</artifactId>
        <version>3.3.0</version>
        <configuration>
          <delimiters>
            <delimiter>@</delimiter>
          </delimiters>
          <useDefaultDelimiters>false</useDefaultDelimiters>
        </configuration>
      </plugin>

      <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
        <configuration>
          <profiles>
            <profile>@env.profile@</profile>
          </profiles>
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>

总结

本文介绍了 Maven Profile 的核心用法:

场景 推荐配置
开发环境 mvn package -Pdev,本地调试用
测试环境 mvn package -Ptest,CI/CD 自动切换
生产环境 mvn package -Pprod,配合环境变量使用

关键点

  • 生产环境的密码不要硬编码,用 ${env.XXX} 读取环境变量
  • 善用 activeByDefault 设置开发环境为默认
  • 多模块项目中在父 POM 统一管理 Profile

🔗 相关文章

上一篇:⚡ Maven 并行构建配置:-T 4C 提速 4 倍的秘密

**下一篇:**🏗️ Maven 多模块项目拆分实战:从单体到微服务的演进之路(即将发布)

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。