Skip to content

使用 Maven Profile 实现分环境打包 tio-boot 项目 ​

在软件开发过程中,不同的运行环境(如开发环境、生产环境、测试环境等)通常需要不同的配置和依赖。Maven 提供了 profiles 功能,允许开发者根据不同的需求切换构建配置,从而实现分环境打包。本指南将详细介绍如何通过 Maven Profile 配置,实现针对开发、生产、二进制包和 GraalVM 原生镜像的分环境构建。

目录 ​

Maven Profiles 概述 ​

Maven Profiles 允许在构建过程中动态地修改项目的配置。通过定义不同的 profiles,可以为不同的环境设置不同的依赖、插件配置、构建参数等。这种机制极大地提升了项目构建的灵活性和可维护性。

配置 Maven Profiles ​

以下是一个示例 pom.xml 中的 profiles 配置,其中定义了四个不同的构建环境:开发环境、生产环境、Assembly 和 Native。

xml
<profiles>
    <!-- 开发环境配置 -->
    <profile>
      <id>development</id>
      <activation>
        <activeByDefault>true</activeByDefault>
      </activation>
      <build>
        <plugins>
          <!-- Spring Boot Maven 插件 -->
          <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <version>2.7.18</version>
            <configuration>
              <fork>true</fork>
              <mainClass>${main.class}</mainClass>
              <excludeGroupIds>org.projectlombok</excludeGroupIds>
              <arguments>
                <argument>--mode=dev</argument>
              </arguments>
            </configuration>
          </plugin>
        </plugins>
      </build>
    </profile>

    <!-- 生产环境配置 -->
    <profile>
      <id>production</id>
      <build>
        <plugins>
          <!-- Spring Boot Maven 插件 -->
          <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <version>2.7.18</version>
            <configuration>
              <mainClass>${main.class}</mainClass>
              <excludeGroupIds>org.projectlombok</excludeGroupIds>
            </configuration>
            <executions>
              <execution>
                <goals>
                  <goal>repackage</goal>
                </goals>
              </execution>
            </executions>
          </plugin>
        </plugins>
      </build>
    </profile>
    <!-- assembly -->
    <profile>
      <id>assembly</id>
      <build>
        <plugins>
          <!-- 组装文件并压缩zip插件 -->
          <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-assembly-plugin</artifactId>
            <version>3.3.0</version>
            <configuration>
              <!-- not append assembly id in release file name -->
              <appendAssemblyId>false</appendAssemblyId>
              <descriptors>
                <descriptor>assembly-${assembly}.xml</descriptor>
              </descriptors>
            </configuration>
            <executions>
              <execution>
                <id>make-assembly</id>
                <phase>package</phase>
                <goals>
                  <goal>single</goal>
                </goals>
              </execution>
            </executions>
          </plugin>
        </plugins>
        <!-- 多模块项目资源配置在classpath下 -->
        <resources>
          <resource>
            <directory>src/main/resources</directory>
            <includes>
              <include>**/*.*</include>
            </includes>
          </resource>
        </resources>
      </build>
    </profile>

  <!-- Native -->
  <profile>
    <id>native</id>
    <dependencies>
      <!-- GraalVM 环境使用 JDK 日志 -->
      <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-jdk14</artifactId>
        <version>1.7.31</version>
      </dependency>
      <!-- GraalVM SDK -->
      <dependency>
        <groupId>org.graalvm.sdk</groupId>
        <artifactId>graal-sdk</artifactId>
        <version>${graalvm.version}</version>
        <scope>provided</scope>
      </dependency>
    </dependencies>
    <build>
      <finalName>${project.artifactId}</finalName>
      <plugins>
        <plugin>
          <groupId>org.graalvm.nativeimage</groupId>
          <artifactId>native-image-maven-plugin</artifactId>
          <version>21.2.0</version>
          <executions>
            <execution>
              <goals>
                <goal>native-image</goal>
              </goals>
              <phase>package</phase>
            </execution>
          </executions>
          <configuration>
            <skip>false</skip>
            <imageName>${project.artifactId}</imageName>
            <mainClass>${main.class}</mainClass>
            <buildArgs>
              -H:+RemoveSaturatedTypeFlows
              --allow-incomplete-classpath
              --no-fallback
            </buildArgs>
          </configuration>
        </plugin>
      </plugins>
    </build>
  </profile>
</profiles>

1. 开发环境 Profile ​

xml
<profile>
  <id>development</id>
  <activation>
    <activeByDefault>true</activeByDefault>
  </activation>
  <dependencies>
    <dependency>
      <groupId>ch.qos.logback</groupId>
      <artifactId>logback-classic</artifactId>
      <version>1.3.3</version>
    </dependency>
  </dependencies>
</profile>
  • 说明:此 Profile 用于开发环境。通过 <activeByDefault>true</activeByDefault>,该 Profile 将作为默认激活的配置,除非在构建时显式指定其他 Profile。
  • 依赖:引入了 logback-classic 日志框架,方便在开发过程中进行日志记录和调试。

2. 生产环境 Profile ​

xml
<profile>
  <id>production</id>
  <dependencies>
    <dependency>
      <groupId>ch.qos.logback</groupId>
      <artifactId>logback-classic</artifactId>
      <version>1.3.3</version>
    </dependency>
  </dependencies>
  <build>
    <plugins>
      <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
        <version>2.7.18</version>
        <configuration>
          <mainClass>${main.class}</mainClass>
          <excludeGroupIds>org.projectlombok</excludeGroupIds>
        </configuration>
        <!-- 设置执行目标 -->
        <executions>
          <execution>
            <goals>
              <goal>repackage</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>
</profile>
  • 说明:此 Profile 专为生产环境设计,包含生产环境所需的依赖和插件配置。
  • 依赖:同样引入 logback-classic,确保生产环境的日志记录。
  • 构建插件:配置了 spring-boot-maven-plugin,通过 repackage 目标,将应用打包为可执行的 Spring Boot JAR 文件。配置中指定了主类 (${main.class}) 并排除了 org.projectlombok 组的依赖,以减少最终包的体积。

3. Assembly Profile ​

xml
<profile>
  <id>assembly</id>
  <dependencies>
    <dependency>
      <groupId>ch.qos.logback</groupId>
      <artifactId>logback-classic</artifactId>
      <version>1.3.3</version>
    </dependency>
  </dependencies>
  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-jar-plugin</artifactId>
        <version>3.2.0</version>
      </plugin>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-assembly-plugin</artifactId>
        <version>3.1.1</version>
        <configuration>
          <archive>
            <manifest>
              <mainClass>${main.class}</mainClass>
            </manifest>
          </archive>
          <descriptorRefs>
            <descriptorRef>jar-with-dependencies</descriptorRef>
          </descriptorRefs>
          <appendAssemblyId>false</appendAssemblyId>
        </configuration>
        <executions>
          <execution>
            <id>make-assembly</id>
            <phase>package</phase>
            <goals>
              <goal>single</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>
</profile>
  • 说明:此 Profile 用于生成包含所有依赖的可执行 JAR 包,适用于需要将应用打包为单一可分发文件的场景。
  • 依赖:依然引入 logback-classic。
  • 构建插件:
    • maven-jar-plugin:负责标准的 JAR 打包过程。
    • maven-assembly-plugin:通过 jar-with-dependencies 描述符,将所有依赖打包到一个 JAR 文件中。配置中指定了主类,并设置 appendAssemblyId 为 false,以避免在最终文件名中添加附加标识。

4. Native Profile ​

xml
<profile>
  <id>native</id>
  <dependencies>
    <!-- GraalVM 环境使用 JDK 日志 -->
    <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-jdk14</artifactId>
      <version>1.7.31</version>
    </dependency>
    <!-- GraalVM SDK -->
    <dependency>
      <groupId>org.graalvm.sdk</groupId>
      <artifactId>graal-sdk</artifactId>
      <version>${graalvm.version}</version>
      <scope>provided</scope>
    </dependency>
  </dependencies>
  <build>
    <finalName>${project.artifactId}</finalName>
    <plugins>
      <plugin>
        <groupId>org.graalvm.nativeimage</groupId>
        <artifactId>native-image-maven-plugin</artifactId>
        <version>21.2.0</version>
        <executions>
          <execution>
            <goals>
              <goal>native-image</goal>
            </goals>
            <phase>package</phase>
          </execution>
        </executions>
        <configuration>
          <skip>false</skip>
          <imageName>${project.artifactId}</imageName>
          <mainClass>${main.class}</mainClass>
          <buildArgs>
            -H:+RemoveSaturatedTypeFlows
            --allow-incomplete-classpath
            --no-fallback
          </buildArgs>
        </configuration>
      </plugin>
    </plugins>
  </build>
</profile>
  • 说明:此 Profile 用于生成 GraalVM 原生镜像,提高应用的启动速度和性能,适用于生产环境中对性能要求较高的场景。
  • 依赖:
    • slf4j-jdk14:使用 JDK 自带的日志框架,适配 GraalVM 环境。
    • graal-sdk:GraalVM 的开发工具包,配置为 provided 作用域,表示在编译时需要,但在运行时由 GraalVM 提供。
  • 构建插件:
    • native-image-maven-plugin:负责将 Java 应用编译为原生镜像。配置中指定了镜像名称、主类以及构建参数,以优化生成的原生镜像。

构建命令 ​

根据不同的 Profile,可以使用以下 Maven 命令进行构建:

为开发环境构建 ​

bash
mvn clean package -DskipTests -Pdevelopment
  • 说明:清理项目并打包,仅激活 development Profile。由于 development Profile 被设置为默认激活,因此即使不指定 -Pdevelopment,也会使用该配置。

为生产环境构建 ​

bash
mvn clean package -DskipTests -Dgpg.skip -Pproduction
  • 说明:清理项目并打包,激活 production Profile。该配置会生成适用于生产环境的可执行 JAR 文件,并排除不必要的依赖以优化包的体积。

为生产环境构建二进制包 ​

bash
mvn clean package -DskipTests -Pnative
  • 说明:清理项目并打包,激活 native Profile。此命令将生成 GraalVM 原生镜像,适用于需要高性能和快速启动的生产环境。

详细解释与说明 ​

1. Profile 激活机制 ​

  • 默认激活:development Profile 通过 <activeByDefault>true</activeByDefault> 设置为默认激活。这意味着在未指定 Profile 时,Maven 会自动使用该配置。
  • 显式激活:通过 -P 参数可以显式指定要激活的 Profile,如 -Pproduction 或 -Pnative。这会覆盖默认激活的 Profile。

2. 依赖管理 ​

不同的 Profile 可以引入不同的依赖,以满足各环境的需求。例如:

  • 开发环境:使用 logback-classic 进行日志记录,便于调试。
  • Native Profile:使用 slf4j-jdk14 适配 GraalVM,并引入 graal-sdk 进行原生镜像构建。

3. 构建插件配置 ​

  • Spring Boot Maven Plugin(生产环境):

    • 通过 repackage 目标,将应用打包为可执行的 Spring Boot JAR 文件。
    • 配置 mainClass 指定应用的主类。
    • 排除 org.projectlombok 组的依赖,减少最终包的体积。
  • Maven Assembly Plugin(Assembly Profile):

    • 使用 jar-with-dependencies 描述符,将所有依赖打包到一个 JAR 文件中,便于分发和部署。
    • 配置 mainClass,确保可执行 JAR 文件正确运行。
  • Native Image Maven Plugin(Native Profile):

    • 将 Java 应用编译为 GraalVM 原生镜像,提高启动速度和性能。
    • 配置 imageName 和 mainClass,以及优化构建参数,如 --no-fallback 以减少镜像体积。

4. 变量与属性 ​

  • ${main.class}:需在 pom.xml 的 <properties> 中定义,指定应用的主类。例如:

    xml
    <properties>
      <main.class>com.example.MainApplication</main.class>
      <graalvm.version>21.3.0</graalvm.version>
    </properties>
  • ${project.artifactId}:Maven 内置变量,表示项目的 artifactId,用于动态命名生成的文件。

总结 ​

通过 Maven Profiles,可以灵活地管理不同环境下的构建配置,简化了项目的构建和部署流程。本指南介绍了如何配置和使用多个 Profile,包括开发、生产、Assembly 和 Native 环境。根据项目的具体需求,可以进一步扩展和定制这些 Profile,以实现更高效的构建过程。

推荐实践:

  • 统一配置:将常用的配置和依赖抽取到公共部分,避免在各个 Profile 中重复定义。
  • 环境变量:结合环境变量或 Maven 的 settings.xml,实现更动态的 Profile 激活和配置管理。
  • 测试与验证:在引入新的 Profile 时,确保在各环境中进行充分的测试,验证构建结果的正确性和稳定性。

通过合理使用 Maven Profiles,开发者可以显著提升项目的可维护性和构建效率,确保在不同环境下应用的稳定运行。

MIT Licensed