一、生命周期与插件体系
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/