源本科技 | 码上会

Maven 多环境配置

2026/03/17
6
0

引言

在云原生开发模式下,应用程序通常需要经历开发(Dev)、测试(Test)、预发布(Stage)和生产(Prod)等多个环境。每个环境的配置(如数据库连接、中间件地址、日志级别等)往往截然不同。

如果为每个环境维护一套独立的代码库或配置文件,不仅会导致代码冗余,还极易引发“配置漂移”,即生产环境与测试环境不一致导致的线上故障。Maven 的 Profiles(构建轮廓) 机制正是为了解决这一痛点而生。它允许我们在同一个项目中定义多套配置,并在构建时动态激活所需的那一套,真正实现“构建一次,到处运行”。


Profiles 机制

什么是 Profiles

Profile 是 Maven 提供的一种条件化构建机制。它允许开发者在 pom.xml 中定义一组特定的配置(如属性、依赖、插件配置等),并根据激活条件(手动指定、操作系统、JDK 版本等)决定是否在当前的构建中生效。

应用场景

  • 多环境配置切换:最典型的用法。通过激活不同的 Profile,自动替换数据库 URL、用户名密码等资源文件中的变量。

  • 依赖管理:某些依赖仅在特定环境下需要(例如开发环境需要热部署工具 spring-boot-devtools,而生产环境不需要)。

  • 构建流程定制:在不同环境下执行不同的插件逻辑(例如生产环境开启代码混淆,开发环境关闭)。

配置实战

定义多环境 Profile

通常在父工程(聚合工程)的 pom.xml 中统一定义所有环境的 Profile,利用继承机制让子模块共享。

<project>
    <!-- ... 基础配置 ... -->

    <profiles>
        <!-- 1. 开发环境 (dev) -->
        <profile>
            <id>dev</id>
            <!-- 设定为默认激活,方便本地开发直接 mvn install -->
            <activation>
                <activeByDefault>true</activeByDefault>
            </activation>
            <properties>
                <env.name>development</env.name>
                <jdbc.url>jdbc:mysql://localhost:3306/dev_db?useSSL=false</jdbc.url>
                <jdbc.username>root</jdbc.username>
                <jdbc.password>local_password</jdbc.password>
                <logging.level>DEBUG</logging.level>
            </properties>
        </profile>

        <!-- 2. 测试环境 (test) -->
        <profile>
            <id>test</id>
            <properties>
                <env.name>testing</env.name>
                <jdbc.url>jdbc:mysql://test-db-cluster:3306/test_db</jdbc.url>
                <jdbc.username>test_user</jdbc.username>
                <jdbc.password>test_secure_pwd</jdbc.password>
                <logging.level>INFO</logging.level>
            </properties>
        </profile>

        <!-- 3. 生产环境 (prod) -->
        <profile>
            <id>prod</id>
            <properties>
                <env.name>production</env.name>
                <jdbc.url>jdbc:mysql://prod-db-cluster:3306/prod_db</jdbc.url>
                <jdbc.username>prod_app_user</jdbc.username>
                <!-- 生产密码建议通过 CI/CD 环境变量注入,此处仅为示例 -->
                <jdbc.password>${ENV_PROD_PASSWORD}</jdbc.password> 
                <logging.level>WARN</logging.level>
            </properties>
        </profile>
    </profiles>
</project>

激活策略

命令行激活(推荐)

在 CI/CD 流水线或手动构建时,通过 -P 参数指定需要激活的 Profile ID。

# 激活测试环境
mvn clean package -P test

# 激活生产环境
mvn clean package -P prod

注意:如果命令行指定了 Profile,activeByDefault 将不再生效。只有未指定任何 -P 参数时,默认 Profile 才会激活。

其他激活方式

  • 文件存在性:当检测到某个特定文件存在时激活(适合本地开发标识)。

  • 系统属性:根据 JDK 版本或操作系统类型自动激活。

  • 环境变量:根据 CI/CD 系统中的环境变量激活。

配合资源过滤

定义了 Profile 中的属性后,必须结合资源过滤功能,才能将这些属性值替换到 src/main/resources 下的配置文件中(如 application.ymljdbc.properties)。

# src/main/resources/application.yml
spring:
  datasource:
    url: ${jdbc.url}
    username: ${jdbc.username}
    password: ${jdbc.password}
  logging:
    level:
      root: ${logging.level}

构建时,Maven 会根据激活的 Profile,将 ${jdbc.url} 替换为对应的真实地址。


构建优化

在敏捷开发和持续集成过程中,测试是保证质量的关键环节。然而,在某些特定场景下(如快速验证构建、紧急修复、或测试代码本身有问题时),我们需要灵活地跳过或筛选测试用例。Maven 通过 maven-surefire-plugin 提供了精细的控制能力。

临时跳过

适用于临时的构建需求,不修改项目代码。

跳过测试执行,但编译测试代码

使用 -DskipTests。Maven 会编译 src/test/java 下的测试类,但不会运行它们。

mvn clean install -DskipTests

适用场景:你想确保测试代码能编译通过(防止语法错误),但暂时不想花费时间运行测试。

完全跳过测试(不编译也不运行)

使用 -Dmaven.test.skip=true。Maven 既不会编译测试代码,也不会运行测试。

mvn clean install -Dmaven.test.skip=true

适用场景:测试代码严重损坏导致构建失败,或者你只关心主业务代码的打包,追求极致速度。

持久化策略

适用于需要长期固定某种测试行为的场景,通常配置在 pom.xml<build><plugins> 部分。

全局跳过测试

skipTests 设置为 true。这通常不建议在主分支中使用,可能用于特定的子模块(如纯工具库模块无测试)或特定的 Profile 中。

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-surefire-plugin</artifactId>
            <version>3.1.2</version> <!-- 建议使用较新版本 -->
            <configuration>
                <skipTests>true</skipTests>
            </configuration>
        </plugin>
    </plugins>
</build>

选择性执行

这是更高级且推荐的用法。你可以指定只运行某些测试,或者排除某些不稳定的测试。

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-surefire-plugin</artifactId>
            <version>3.1.2</version>
            <configuration>
                <!-- 是否跳过测试 -->
                <skipTests>false</skipTests>
                
                <!-- 排除特定的测试类(支持通配符) -->
                <excludes>
                    <exclude>**/SlowIntegrationTest.java</exclude>
                    <exclude>**/*ManualTest.java</exclude>
                </excludes>
                
                <!-- 只包含特定的测试类 -->
                <includes>
                    <include>**/UnitTestCase.java</include>
                    <include>**/*SmokeTest.java</include>
                </includes>
            </configuration>
        </plugin>
    </plugins>
</build>

最佳实践:可以将不同的测试策略绑定到不同的 Profile 中。例如,创建一个 fast-build Profile,其中配置排除耗时的集成测试,仅运行单元测试,以便开发人员快速反馈。