Maven 构建工程化指南

一、生命周期与插件体系

1.1 三层生命周期

#mermaid-svg-iZ0flR2RiISYvZYc{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-iZ0flR2RiISYvZYc .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-iZ0flR2RiISYvZYc .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-iZ0flR2RiISYvZYc .error-icon{fill:#552222;}#mermaid-svg-iZ0flR2RiISYvZYc .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-iZ0flR2RiISYvZYc .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-iZ0flR2RiISYvZYc .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-iZ0flR2RiISYvZYc .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-iZ0flR2RiISYvZYc .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-iZ0flR2RiISYvZYc .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-iZ0flR2RiISYvZYc .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-iZ0flR2RiISYvZYc .marker{fill:#333333;stroke:#333333;}#mermaid-svg-iZ0flR2RiISYvZYc .marker.cross{stroke:#333333;}#mermaid-svg-iZ0flR2RiISYvZYc svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-iZ0flR2RiISYvZYc p{margin:0;}#mermaid-svg-iZ0flR2RiISYvZYc .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-iZ0flR2RiISYvZYc .cluster-label text{fill:#333;}#mermaid-svg-iZ0flR2RiISYvZYc .cluster-label span{color:#333;}#mermaid-svg-iZ0flR2RiISYvZYc .cluster-label span p{background-color:transparent;}#mermaid-svg-iZ0flR2RiISYvZYc .label text,#mermaid-svg-iZ0flR2RiISYvZYc span{fill:#333;color:#333;}#mermaid-svg-iZ0flR2RiISYvZYc .node rect,#mermaid-svg-iZ0flR2RiISYvZYc .node circle,#mermaid-svg-iZ0flR2RiISYvZYc .node ellipse,#mermaid-svg-iZ0flR2RiISYvZYc .node polygon,#mermaid-svg-iZ0flR2RiISYvZYc .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-iZ0flR2RiISYvZYc .rough-node .label text,#mermaid-svg-iZ0flR2RiISYvZYc .node .label text,#mermaid-svg-iZ0flR2RiISYvZYc .image-shape .label,#mermaid-svg-iZ0flR2RiISYvZYc .icon-shape .label{text-anchor:middle;}#mermaid-svg-iZ0flR2RiISYvZYc .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-iZ0flR2RiISYvZYc .rough-node .label,#mermaid-svg-iZ0flR2RiISYvZYc .node .label,#mermaid-svg-iZ0flR2RiISYvZYc .image-shape .label,#mermaid-svg-iZ0flR2RiISYvZYc .icon-shape .label{text-align:center;}#mermaid-svg-iZ0flR2RiISYvZYc .node.clickable{cursor:pointer;}#mermaid-svg-iZ0flR2RiISYvZYc .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-iZ0flR2RiISYvZYc .arrowheadPath{fill:#333333;}#mermaid-svg-iZ0flR2RiISYvZYc .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-iZ0flR2RiISYvZYc .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-iZ0flR2RiISYvZYc .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-iZ0flR2RiISYvZYc .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-iZ0flR2RiISYvZYc .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-iZ0flR2RiISYvZYc .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-iZ0flR2RiISYvZYc .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-iZ0flR2RiISYvZYc .cluster text{fill:#333;}#mermaid-svg-iZ0flR2RiISYvZYc .cluster span{color:#333;}#mermaid-svg-iZ0flR2RiISYvZYc div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-iZ0flR2RiISYvZYc .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-iZ0flR2RiISYvZYc rect.text{fill:none;stroke-width:0;}#mermaid-svg-iZ0flR2RiISYvZYc .icon-shape,#mermaid-svg-iZ0flR2RiISYvZYc .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-iZ0flR2RiISYvZYc .icon-shape p,#mermaid-svg-iZ0flR2RiISYvZYc .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-iZ0flR2RiISYvZYc .icon-shape .label rect,#mermaid-svg-iZ0flR2RiISYvZYc .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-iZ0flR2RiISYvZYc .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-iZ0flR2RiISYvZYc .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-iZ0flR2RiISYvZYc :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} site 生命周期
pre-site
site
post-site
site-deploy
default 生命周期
validate
compile
test
package
verify
install
deploy
clean 生命周期
pre-clean
clean
post-clean

关键阶段详解

阶段 执行内容 典型绑定插件
compile 编译源码 maven-compiler-plugin
test 运行单元测试 maven-surefire-plugin
package 打包(jar/war) maven-jar-plugin / maven-war-plugin
verify 集成测试验证 maven-failsafe-plugin
install 安装到本地仓库 maven-install-plugin
deploy 部署到远程仓库 maven-deploy-plugin

1.2 插件执行与跳过

bash 复制代码
# 跳过测试代码的编译和执行
mvn package -Dmaven.test.skip=true

# 编译测试代码,但不执行
mvn package -DskipTests

# 跳过某个特定插件
mvn package -Dcheckstyle.skip=true -Dpmd.skip=true

# 只执行到 compile 阶段
mvn compile

# 跳跃执行: 直接 package (会触发之前所有阶段)
mvn package -pl my-module -am    # -am = also-make, 先编译依赖模块

1.3 查看构建详情

bash 复制代码
# 查看生效的插件配置
mvn help:effective-pom

# 查看依赖树
mvn dependency:tree

# 查看当前激活的 profile
mvn help:active-profiles

# 显示每个模块的构建耗时
mvn clean install -Dmaven.build.timestamp.format=HH:mm:ss

# 查看构建依赖关系图
mvn com.github.ferstl:depgraph-maven-plugin:graph

二、多模块项目构建策略

2.1 模块划分原则

复制代码
推荐的项目结构:
  parent/                      ← 父 POM (dependencyManagement + pluginManagement)
  ├── common/                  ← 公共模块 (DTO、工具类、常量)
  ├── domain/                  ← 领域层 (Entity、Repository接口)
  ├── infrastructure/          ← 基础设施 (DAO、外部API适配、消息)
  ├── application/             ← 应用层 (Service、UseCase)
  ├── api/                     ← API 层 (Controller、DTO转换)
  └── assembly/                ← 打包模块 (仅含 assembly 描述符)

反模式 ------ 避免的模块划分:
  model/ service/ dao/ controller/   ← 这种分层方式导致每层依赖混乱

2.2 父 POM 最佳实践

xml 复制代码
<!-- parent/pom.xml -->
<project>
    <modelVersion>4.0.0</modelVersion>
    
    <groupId>com.example</groupId>
    <artifactId>app-parent</artifactId>
    <version>1.0.0-SNAPSHOT</version>
    <packaging>pom</packaging>
    
    <modules>
        <module>common</module>
        <module>domain</module>
        <module>infrastructure</module>
        <module>application</module>
        <module>api</module>
        <module>assembly</module>
    </modules>
    
    <!-- ===== 统一版本管理 ===== -->
    <properties>
        <java.version>17</java.version>
        <spring-boot.version>3.3.0</spring-boot.version>
        <guava.version>33.2.0-jre</guava.version>
        <mapstruct.version>1.5.5.Final</mapstruct.version>
        <!-- 插件版本 -->
        <maven-compiler-plugin.version>3.13.0</maven-compiler-plugin.version>
    </properties>
    
    <!-- dependencyManagement: 只声明版本,不引入依赖 -->
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring-boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
    
    <!-- ===== 统一插件配置 ===== -->
    <build>
        <pluginManagement>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <version>${maven-compiler-plugin.version}</version>
                    <configuration>
                        <source>${java.version}</source>
                        <target>${java.version}</target>
                        <parameters>true</parameters>  <!-- 保留参数名 -->
                    </configuration>
                </plugin>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-surefire-plugin</artifactId>
                    <version>3.3.0</version>
                </plugin>
            </plugins>
        </pluginManagement>
    </build>
</project>

2.3 选择性构建

bash 复制代码
# 只构建指定模块及其依赖
mvn clean install -pl api -am
# -pl: 指定模块
# -am: also-make, 自动构建该模块依赖的兄弟模块

# 只构建指定模块及其下游
mvn clean install -pl common -amd
# -amd: also-make-dependents, 构建依赖 common 的模块

# 从根构建所有模块
mvn clean install
# 跳过集成测试,只跑单元测试
mvn clean install -DskipITs=true

三、依赖治理与冲突解决

3.1 依赖冲突诊断

bash 复制代码
# 查看完整依赖树
mvn dependency:tree

# 只看冲突部分 (显示省略和冲突)
mvn dependency:tree -Dverbose=true

# 查找特定依赖的来源
mvn dependency:tree -Dincludes=com.google.guava:guava

# 查看依赖分析报告
mvn dependency:analyze
# 输出:
#   Used undeclared dependencies:  使用了但未声明的依赖
#   Unused declared dependencies:  声明了但未使用的依赖

3.2 排除传递性依赖

xml 复制代码
<!-- 方式一: 在依赖声明中排除 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <exclusions>
        <!-- 排除 Jackson,改用 Gson -->
        <exclusion>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
        </exclusion>
        <!-- 排除 Tomcat,改用 Undertow -->
        <exclusion>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
        </exclusion>
    </exclusions>
</dependency>

3.3 BOM 统一版本

xml 复制代码
<!-- 项目中统一导入 BOM,避免版本碎片化 -->
<dependencyManagement>
    <dependencies>
        <!-- Spring Boot BOM -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-dependencies</artifactId>
            <version>3.3.0</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
        <!-- 公司内部 BOM -->
        <dependency>
            <groupId>com.company</groupId>
            <artifactId>company-bom</artifactId>
            <version>2024.1</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

3.4 Maven Enforcer 强制规则

xml 复制代码
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-enforcer-plugin</artifactId>
    <executions>
        <execution>
            <id>enforce</id>
            <goals><goal>enforce</goal></goals>
            <configuration>
                <rules>
                    <!-- 禁止依赖冲突 -->
                    <dependencyConvergence/>
                    <!-- 要求最低 Maven 版本 -->
                    <requireMavenVersion>
                        <version>3.9.0</version>
                    </requireMavenVersion>
                    <!-- 要求最低 Java 版本 -->
                    <requireJavaVersion>
                        <version>17</version>
                    </requireJavaVersion>
                    <!-- 禁止使用某些依赖 -->
                    <bannedDependencies>
                        <excludes>
                            <exclude>commons-logging:commons-logging</exclude>
                            <exclude>log4j:log4j</exclude>
                        </excludes>
                    </bannedDependencies>
                </rules>
            </configuration>
        </execution>
    </executions>
</plugin>

四、构建性能优化

4.1 并行构建

bash 复制代码
# 按模块并行构建 (每个模块一个线程)
mvn clean install -T 4            # 4 个并行线程
mvn clean install -T 1C           # 每核心一个线程
mvn clean install -T 2C           # 每核心两个线程

# 并行运行测试
mvn test -T 1C -DforkCount=1C     # 测试也 fork 到多进程

# 在 settings.xml 或 .mvn/maven.config 中持久化
# .mvn/maven.config:
# -T 2C
# -Dmaven.test.skip=true  (本地开发跳过测试)

4.2 增量构建与缓存

bash 复制代码
# 只构建变更模块
mvn install -pl changed-module -am

# 从离线仓库构建 (不检查远程更新)
mvn package -o

# 跳过所有非必要插件
mvn package -Dcheckstyle.skip -Dpmd.skip -Djacoco.skip

# Maven Daemon (mvnd) 守护进程加速
# 安装: https://github.com/apache/maven-mvnd
mvnd clean install                # 比 mvn 快 2-10 倍!
mvnd clean install -T 4

4.3 Maven Daemon 配置

xml 复制代码
<!-- .mvn/mvnd.yaml -->
javaHome: /path/to/jdk17
mavenHome: /path/to/maven
properties:
  skipTests: true
  checkstyle.skip: true
bash 复制代码
# mvnd vs mvn 性能对比 (典型多模块项目)
# mvn clean install -T 4    → 2m 34s
# mvnd clean install         → 0m 42s  (约 3.6x 提升)

4.4 构建耗时分析

xml 复制代码
<!-- 使用 build-time-profiler 分析耗时 -->
<plugin>
    <groupId>io.github.khmarbaise</groupId>
    <artifactId>maven-profiler-plugin</artifactId>
    <version>1.4</version>
    <executions>
        <execution>
            <goals><goal>profile</goal></goals>
        </execution>
    </executions>
</plugin>
bash 复制代码
# 输出示例:
# [INFO] Module common:
#   compile      : 3.2s
#   testCompile  : 1.1s
#   test         : 12.5s    ← 瓶颈!
#   package      : 0.8s

五、打包策略:JAR/WAR/Docker

5.1 Spring Boot Fat JAR 优化

xml 复制代码
<!-- 将三方依赖单独打出,应用代码单独打包 -->
<!-- 适合 Docker 分层构建,利用缓存 -->
<plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
    <configuration>
        <layers>
            <enabled>true</enabled>
            <includeLayerTools>true</includeLayerTools>
        </layers>
    </configuration>
</plugin>

分层 JAR 在 Dockerfile 中的利用

dockerfile 复制代码
FROM eclipse-temurin:17-jre-alpine
WORKDIR /app

# 从构建产物中提取分层 JAR
COPY --from=builder target/*.jar app.jar
RUN java -Djarmode=layertools -jar app.jar extract

# 分层 COPY (利用 Docker 缓存)
COPY --from=builder dependencies/ ./
COPY --from=builder spring-boot-loader/ ./
COPY --from=builder snapshot-dependencies/ ./
COPY --from=builder application/ ./

ENTRYPOINT ["java", "org.springframework.boot.loader.launch.JarLauncher"]

5.2 Assembly Plugin 打包

xml 复制代码
<!-- assembly.xml: 自定义打包描述符 -->
<assembly>
    <id>distribution</id>
    <formats>
        <format>tar.gz</format>
        <format>zip</format>
    </formats>
    <includeBaseDirectory>true</includeBaseDirectory>
    
    <dependencySets>
        <!-- 依赖 JAR → lib/ -->
        <dependencySet>
            <outputDirectory>lib</outputDirectory>
            <useProjectArtifact>false</useProjectArtifact>
        </dependencySet>
    </dependencySets>
    
    <fileSets>
        <!-- 启动脚本 → bin/ -->
        <fileSet>
            <directory>src/main/bin</directory>
            <outputDirectory>bin</outputDirectory>
            <fileMode>0755</fileMode>
        </fileSet>
        <!-- 配置文件 → conf/ -->
        <fileSet>
            <directory>src/main/resources</directory>
            <outputDirectory>conf</outputDirectory>
        </fileSet>
    </fileSets>
</assembly>

5.3 Jib 免 Dockerfile 构建镜像

xml 复制代码
<!-- 无需安装 Docker,直接构建并推送镜像 -->
<plugin>
    <groupId>com.google.cloud.tools</groupId>
    <artifactId>jib-maven-plugin</artifactId>
    <version>3.4.3</version>
    <configuration>
        <from>
            <image>eclipse-temurin:17-jre-alpine</image>
        </from>
        <to>
            <image>registry.example.com/${project.artifactId}:${project.version}</image>
            <tags>
                <tag>latest</tag>
            </tags>
        </to>
        <container>
            <jvmFlags>
                <flag>-XX:MaxRAMPercentage=75.0</flag>
                <flag>-XX:+UseG1GC</flag>
            </jvmFlags>
            <ports><port>8080</port></ports>
        </container>
    </configuration>
</plugin>
bash 复制代码
# 构建并推送 Docker 镜像
mvn compile jib:build

# 只构建不推送 (本地 Docker daemon)
mvn compile jib:dockerBuild

六、Profile 多环境构建

6.1 Profile 定义

xml 复制代码
<profiles>
    <!-- 开发环境 -->
    <profile>
        <id>dev</id>
        <activation>
            <activeByDefault>true</activeByDefault>
        </activation>
        <properties>
            <env>dev</env>
            <db.url>jdbc:h2:mem:devdb</db.url>
        </properties>
    </profile>
    
    <!-- 测试环境 -->
    <profile>
        <id>staging</id>
        <properties>
            <env>staging</env>
            <db.url>jdbc:mysql://staging-db:3306/app</db.url>
        </properties>
    </profile>
    
    <!-- 生产环境 -->
    <profile>
        <id>prod</id>
        <properties>
            <env>prod</env>
            <db.url>jdbc:mysql://prod-db:3306/app</db.url>
        </properties>
    </profile>
</profiles>

6.2 资源过滤

xml 复制代码
<build>
    <resources>
        <resource>
            <directory>src/main/resources</directory>
            <filtering>true</filtering>   <!-- 启用变量替换 -->
            <includes>
                <include>application.yml</include>
            </includes>
        </resource>
        <resource>
            <directory>src/main/resources</directory>
            <filtering>false</filtering>  <!-- 静态资源不过滤 -->
            <excludes>
                <exclude>application.yml</exclude>
            </excludes>
        </resource>
    </resources>
</build>
yaml 复制代码
# application.yml 中使用 Maven 属性
spring:
  datasource:
    url: ${db.url}
  profiles:
    active: @env@      # @env@ 会被 Maven profile 替换
bash 复制代码
# 按环境打包
mvn clean package -P staging
mvn clean package -P prod

七、私有仓库与制品管理

7.1 settings.xml 配置

xml 复制代码
<!-- ~/.m2/settings.xml -->
<settings>
    <mirrors>
        <!-- 阿里云镜像加速 -->
        <mirror>
            <id>aliyun</id>
            <mirrorOf>central</mirrorOf>
            <url>https://maven.aliyun.com/repository/public</url>
        </mirror>
    </mirrors>
    
    <servers>
        <!-- 私有仓库认证 -->
        <server>
            <id>company-releases</id>
            <username>${env.NEXUS_USER}</username>
            <password>${env.NEXUS_PASS}</password>
        </server>
        <server>
            <id>company-snapshots</id>
            <username>${env.NEXUS_USER}</username>
            <password>${env.NEXUS_PASS}</password>
        </server>
    </servers>
    
    <profiles>
        <profile>
            <id>company</id>
            <repositories>
                <repository>
                    <id>company-releases</id>
                    <url>https://nexus.company.com/repository/maven-releases/</url>
                    <releases><enabled>true</enabled></releases>
                    <snapshots><enabled>false</enabled></snapshots>
                </repository>
                <repository>
                    <id>company-snapshots</id>
                    <url>https://nexus.company.com/repository/maven-snapshots/</url>
                    <releases><enabled>false</enabled></releases>
                    <snapshots><enabled>true</enabled></snapshots>
                </repository>
            </repositories>
        </profile>
    </profiles>
    
    <activeProfiles>
        <activeProfile>company</activeProfile>
    </activeProfiles>
</settings>

7.2 版本号管理策略

xml 复制代码
<!-- 使用 versions-maven-plugin 管理版本 -->
<!-- 查看可用的依赖更新 -->
mvn versions:display-dependency-updates

<!-- 查看可用的插件更新 -->
mvn versions:display-plugin-updates

<!-- 查看可用的父 POM 更新 -->
mvn versions:display-parent-updates

<!-- 自动更新到最新版本 (谨慎!) -->
mvn versions:use-latest-releases
xml 复制代码
<!-- 语义化版本 + SNAPSHOT 约定 -->
<!-- 开发阶段: 1.0.0-SNAPSHOT -->
<!-- 发布候选: 1.0.0-RC1       -->
<!-- 正式发布: 1.0.0             -->
<!-- 热修复:   1.0.1             -->

八、CI/CD 流水线集成

8.1 GitHub Actions 示例

yaml 复制代码
# .github/workflows/maven-ci.yml
name: Maven CI

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      
      - name: Set up JDK 17
        uses: actions/setup-java@v4
        with:
          java-version: '17'
          distribution: 'temurin'
          cache: maven        # 自动缓存 .m2/repository
      
      - name: Build with Maven
        run: |
          mvn -B clean verify \
            -Dmaven.test.failure.ignore=false \
            -Dcheckstyle.skip=false
        env:
          NEXUS_USER: ${{ secrets.NEXUS_USER }}
          NEXUS_PASS: ${{ secrets.NEXUS_PASS }}
      
      - name: Publish test results
        if: always()
        uses: dorny/test-reporter@v1
        with:
          name: Maven Tests
          path: '**/target/surefire-reports/*.xml'
          reporter: java-junit

8.2 Jenkins Pipeline 示例

groovy 复制代码
// Jenkinsfile
pipeline {
    agent any
    
    tools {
        maven 'maven-3.9'
        jdk 'jdk-17'
    }
    
    stages {
        stage('Checkout') {
            steps {
                checkout scm
            }
        }
        
        stage('Build & Test') {
            steps {
                sh '''
                    mvn clean verify \
                      -T 2C \
                      -Dmaven.test.failure.ignore=false
                '''
            }
        }
        
        stage('SonarQube Analysis') {
            steps {
                withSonarQubeEnv('SonarQube') {
                    sh 'mvn sonar:sonar'
                }
            }
        }
        
        stage('Deploy to Nexus') {
            when { branch 'main' }
            steps {
                sh 'mvn deploy -DskipTests -Dcheckstyle.skip'
            }
        }
        
        stage('Build Docker Image') {
            when { branch 'main' }
            steps {
                sh 'mvn compile jib:build -pl api'
            }
        }
    }
    
    post {
        failure {
            // 构建失败通知
            dingtalk(
                robot: 'robot-id',
                message: "构建失败: ${env.JOB_NAME} #${env.BUILD_NUMBER}"
            )
        }
    }
}

8.3 Maven Wrapper

bash 复制代码
# 生成 Maven Wrapper (确保团队使用相同 Maven 版本)
mvn wrapper:wrapper -Dmaven=3.9.8

# 之后统一使用 ./mvnw 代替 mvn
./mvnw clean package               # Windows
./mvnw clean package               # Linux/Mac

# 提交到 Git
git add .mvn/ mvnw mvnw.cmd
git commit -m "Add Maven Wrapper 3.9.8"

8.4 构建缓存策略

xml 复制代码
<!-- .mvn/maven.config: 项目级 Maven 配置 -->
-T 2C
-Dmaven.test.failure.ignore=false
-Dcheckstyle.skip=true
-Dmaven.javadoc.skip=true
-ntp                                 <!-- 不下载插件描述符,加速 -->
bash 复制代码
# CI 中缓存 .m2/repository
# GitLab CI 示例:
cache:
  key: ${CI_COMMIT_REF_SLUG}
  paths:
    - .m2/repository/
相关推荐
宠友信息1 小时前
从重复请求到订单同步看内容社区源码的处理思路
java·spring boot·redis·后端·mysql·spring
带刺的坐椅1 小时前
用 Solon TeamAgent 落地供应链异常管理与自动补货
java·ai·llm·agent·solon·供应链
潇凝子潇1 小时前
UnsupportedOperationException
java·前端·数据库
qq_33776320192 小时前
国际期货资管系统开发方案|内外盘交易平台源码授权与二次开发支持
java·c语言·开发语言·c++·c#
不定积分要+C_yyy2 小时前
Java关键字final三种用法、核心特性与高频易错点
java·开发语言
xexpertS4 小时前
队列积压治理:如何避免异步系统出现难以恢复的消息积压
java·开发语言
阿维的博客日记12 小时前
MultipartFile 是不是表示仅仅是一个分片?
java·后端·spring·multipartfile
程序员无隅12 小时前
Coding Agent 为什么压缩上下文后还能继续工作?上下文模块设计拆解
java·开发语言·数据库
Python+9912 小时前
Java 枚举类(Enum)详解:从基础到高级应用
java·开发语言·python