Maven Wrapper 深入讲解与实战:让团队构建环境真正一致

欢迎你来读这篇博客,这篇博客主要是关于 Maven Wrapper 的完整讲解与工程化落地。

Maven Wrapper 看起来只是多了两个脚本:mvnwmvnw.cmd,但它真正解决的是团队协作里非常现实的问题:同一个项目,到底应该用哪个 Maven 版本构建

很多构建问题并不是代码错了,而是 A 同事本地 Maven 3.6,B 同事本地 Maven 3.9,CI 又是另一个版本。最后大家一起围着构建日志开会,场面非常热闹,但没有生产力。

Maven Wrapper 的价值就是:把 Maven 版本和启动方式收进项目本身,让开发机、IDE、CI/CD、临时构建环境尽量使用同一套 Maven 入口。

序言

在 Java 项目里,我们通常会直接执行:

1
mvn clean install

这条命令默认使用的是当前机器 PATH 里找到的 Maven。这意味着项目构建结果会受到本机 Maven 安装版本的影响。

对于个人项目,这通常没什么问题。但对于团队项目、企业项目、CI/CD、开源项目来说,这就会带来几个典型问题:

  1. 新同事拉代码后,不知道该安装哪个 Maven 版本。
  2. 本地构建通过,CI 构建失败。
  3. CI 构建通过,本地 IDEA Reload Maven Project 报错。
  4. Maven 3.8、3.9、4.x 对部分配置、插件校验、.mvn/maven.config 解析存在差异。
  5. 公司私服、代理、内网环境下,Maven 下载入口混乱。

Maven Wrapper 的核心目标不是让 Maven 跑得更快,而是让 Maven 跑得更一致

一句话总结:

mvn 是使用本机 Maven;mvnw 是使用项目指定的 Maven。

正文

1. Maven Wrapper 是什么

Maven Wrapper 是一组可以提交到项目仓库里的 Maven 启动脚本。项目中加入 Maven Wrapper 后,使用者不需要提前在本机安装指定版本的 Maven,而是直接执行项目自带的脚本:

1
./mvnw clean install

Windows 下执行:

1
mvnw.cmd clean install

Wrapper 会根据项目里的配置下载指定版本的 Maven,并使用这个 Maven 来执行构建。后续再次执行时,会复用已经下载好的 Maven 发行包。

官方文档对它的定位也很直接:Maven Wrapper 是一种确保 Maven 构建使用者具备运行该构建所需环境的简单方式。它会在用户缺少指定 Maven 版本时自动下载、安装并使用该版本。

1.1 没有 Wrapper 的构建

flowchart LR
    A[开发者执行 mvn clean install] --> B{本机 PATH 里的 Maven 是什么版本?}
    B --> C[Maven 3.6.x]
    B --> D[Maven 3.8.x]
    B --> E[Maven 3.9.x]
    C --> F[构建结果 A]
    D --> G[构建结果 B]
    E --> H[构建结果 C]

这种方式最大的问题是:项目没有明确控制 Maven 版本

1.2 有 Wrapper 的构建

flowchart LR
    A[开发者执行 ./mvnw clean install] --> B[读取 .mvn/wrapper/maven-wrapper.properties]
    B --> C{本地是否已有指定 Maven 版本?}
    C -- 有 --> D[使用指定 Maven 执行构建]
    C -- 没有 --> E[下载指定 Maven 发行包]
    E --> F[解压到本地 wrapper 缓存目录]
    F --> D

有了 Maven Wrapper 后,项目自己就能说明:“我应该用 Maven 3.9.16 构建,而不是你电脑里随便哪个 Maven”。

这就是 Maven Wrapper 的最大价值。

2. Maven Wrapper 解决什么,不解决什么

Maven Wrapper 很有用,但别把它当万能胶。它解决的是 Maven 版本入口一致性,不是所有构建问题。

工具 解决的问题 是否主要提速 是否固定 Maven 版本
mvn 使用本机 Maven 执行构建
mvnw / mvnw.cmd 使用项目指定 Maven 执行构建
mvnd 通过 Daemon 加速 Maven 构建 间接,由 mvnd 自带 Maven 决定
Maven Build Cache Extension 复用构建产物,减少重复构建

所以它们不是互斥关系。

我的建议是:

1
2
3
4
团队标准构建:./mvnw clean verify
本地快速构建:mvnd clean install -DskipTests
CI 稳定构建:./mvnw -B -ntp clean verify
构建产物加速:Maven Build Cache Extension

mvnw 负责“不乱”,mvnd 负责“更快”。让赛车跑得快之前,方向盘得先装对。

3. Maven Wrapper 会生成哪些文件

在项目根目录执行:

1
mvn wrapper:wrapper

或者指定 Maven 版本:

1
mvn wrapper:wrapper -Dmaven=3.9.16

一般会生成这些文件:

1
2
3
4
5
6
7
project-root/
├── mvnw
├── mvnw.cmd
├── .mvn/
│ └── wrapper/
│ └── maven-wrapper.properties
└── pom.xml

不同 type 下还可能出现:

1
2
.mvn/wrapper/maven-wrapper.jar
.mvn/wrapper/MavenWrapperDownloader.java

当前 Maven Wrapper 新安装默认使用 only-script 类型,这种类型只需要 wrapper 脚本,不需要把 maven-wrapper.jarMavenWrapperDownloader.java 放进仓库。

3.1 文件职责说明

文件 作用 是否应该提交 Git
mvnw Linux/macOS 下的 Maven Wrapper 启动脚本
mvnw.cmd Windows 下的 Maven Wrapper 启动脚本
.mvn/wrapper/maven-wrapper.properties 指定 Maven 发行包下载地址、Wrapper 类型、校验和等
.mvn/wrapper/maven-wrapper.jar bin 类型下用于下载和启动 Maven 的 jar 视团队规范
.mvn/wrapper/MavenWrapperDownloader.java source 类型下动态编译用于下载 Wrapper jar 的 Java 源码 视团队规范

最关键的是:mvnwmvnw.cmd.mvn/wrapper/maven-wrapper.properties 应该提交到仓库。

不提交这几个文件,就像给别人发车钥匙但忘了发车,礼貌但没用。

4. maven-wrapper.properties 详解

一个常见的 .mvn/wrapper/maven-wrapper.properties 可能长这样:

1
2
3
4
5
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements.

distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.16/apache-maven-3.9.16-bin.zip
distributionType=only-script

某些生成方式下也可能包含:

1
2
3
wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.3.4/maven-wrapper-3.3.4.jar
distributionSha256Sum=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
wrapperSha256Sum=yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy

4.1 distributionUrl

distributionUrl 表示 Maven 发行包下载地址。

例如:

1
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.16/apache-maven-3.9.16-bin.zip

这表示项目要求使用 Maven 3.9.16

如果你在企业内网环境中,不能直接访问 Maven Central,可以把它改成公司 Nexus / Artifactory 代理后的地址。

例如:

1
distributionUrl=https://nexus.example.com/repository/maven-public/org/apache/maven/apache-maven/3.9.16/apache-maven-3.9.16-bin.zip

4.2 distributionType

distributionType 表示 Wrapper 分发类型。官方当前提供 4 种类型:

类型 说明 是否提交二进制 jar 适用场景
only-script 默认类型,脚本直接下载 Maven 发行包,不使用 wrapper jar 推荐默认使用
script 脚本方式,必要时下载 wrapper jar 兼容老习惯
bin 提交 .mvn/wrapper/maven-wrapper.jar 不能依赖 curl/wget/PowerShell 的环境
source 提交 MavenWrapperDownloader.java,运行时编译下载 不允许提交 jar 但可以运行 javac 的环境

一般企业项目推荐:

1
mvn wrapper:wrapper -Dmaven=3.9.16 -Dtype=only-script

如果公司安全规范要求所有二进制来源都可审计,only-scriptbin 更清爽。

如果构建环境没有 curlwget、PowerShell,或者网络限制比较奇怪,可以考虑 bin。但提交 jar 进仓库之前,最好先过安全规范。

4.3 distributionSha256Sum

distributionSha256Sum 用来校验下载下来的 Maven 发行包是否被篡改。

示例:

1
distributionSha256Sum=0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef

注意:这里要填的是 SHA-256,不是 SHA-512。

官方 Maven 下载页通常会提供 .sha512 文件,但 Maven Wrapper 这里的属性名是 distributionSha256Sum。如果你要填这个值,可以下载目标 Maven 发行包后自己计算:

macOS / Linux:

1
2
curl -LO https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.16/apache-maven-3.9.16-bin.zip
shasum -a 256 apache-maven-3.9.16-bin.zip

Linux 也可以:

1
sha256sum apache-maven-3.9.16-bin.zip

Windows PowerShell:

1
Get-FileHash .\apache-maven-3.9.16-bin.zip -Algorithm SHA256

把输出的十六进制值填到 distributionSha256Sum

4.4 wrapperSha256Sum

wrapperSha256Sum 用来校验 maven-wrapper.jar

如果你使用的是 only-script,一般不需要这个属性。只有当你的 Wrapper 类型涉及 maven-wrapper.jar 下载或使用时,这个值才更重要。

4.5 alwaysDownload 与 alwaysUnpack

Maven Wrapper Plugin 还支持:

1
2
alwaysDownload=false
alwaysUnpack=false

这两个配置通常不需要改。

配置 含义 建议
alwaysDownload 每次执行 wrapper 都重新下载 Maven 发行包 默认 false
alwaysUnpack 每次执行 wrapper 都重新解压 Maven 发行包 默认 false

除非你在调试 Wrapper 行为,否则别乱开。构建已经够忙了,不要让它每次都重新搬家。

5. Maven Wrapper 的执行流程

下面用一个更完整的流程图看一下:

sequenceDiagram
    participant Dev as Developer / CI
    participant Script as mvnw / mvnw.cmd
    participant Props as maven-wrapper.properties
    participant Cache as ~/.m2/wrapper/dists
    participant Repo as Maven Central / 私服代理
    participant Maven as 指定版本 Maven

    Dev->>Script: ./mvnw clean verify
    Script->>Props: 读取 distributionUrl
    Script->>Cache: 检查目标 Maven 是否已下载
    alt 缓存命中
        Cache-->>Script: 返回已安装 Maven 路径
    else 缓存未命中
        Script->>Repo: 下载 Maven 发行包
        Repo-->>Script: apache-maven-x.y.z-bin.zip
        Script->>Cache: 解压并缓存
    end
    Script->>Maven: 调用指定 Maven
    Maven-->>Dev: 输出构建结果

默认情况下,Wrapper 下载的 Maven 会放在用户目录下的 Wrapper 缓存中,例如:

1
~/.m2/wrapper/dists

如果你希望改变 Maven 发行包安装基础目录,可以设置:

1
export MAVEN_USER_HOME=/data/maven-user-home

然后执行:

1
./mvnw clean verify

这在 CI/CD 容器、共享构建机、磁盘隔离场景里会比较有用。

6. 实战一:给 Spring Boot 项目添加 Maven Wrapper

假设你有一个 Spring Boot 项目:

1
2
3
4
5
6
mall-service/
├── pom.xml
├── src/
│ ├── main/
│ └── test/
└── README.md

现在希望统一使用 Maven 3.9.16

6.1 在项目根目录生成 Wrapper

推荐显式指定 Wrapper Plugin 版本和 Maven 版本:

1
2
3
4
5
cd mall-service

mvn org.apache.maven.plugins:maven-wrapper-plugin:3.3.4:wrapper \
-Dmaven=3.9.16 \
-Dtype=only-script

生成后查看:

1
find . -maxdepth 3 -type f | sort

预期能看到:

1
2
3
4
./.mvn/wrapper/maven-wrapper.properties
./mvnw
./mvnw.cmd
./pom.xml

6.2 给 mvnw 加执行权限

macOS / Linux:

1
chmod +x mvnw

验证:

1
./mvnw -v

正常情况下会看到 Maven 3.9.16

6.3 用 Wrapper 构建项目

1
./mvnw clean verify

跳过测试:

1
./mvnw clean install -DskipTests

批处理模式,适合 CI:

1
./mvnw -B -ntp clean verify

参数说明:

参数 作用
-B Batch mode,减少交互,适合 CI
-ntp no transfer progress,减少下载进度刷屏
clean verify 清理并执行完整验证阶段

6.4 提交到 Git

1
2
git add mvnw mvnw.cmd .mvn/wrapper/maven-wrapper.properties
git commit -m "Add Maven Wrapper"

建议补充 .gitattributes,避免 Windows/macOS/Linux 换行符把脚本搞坏:

1
2
3
mvnw text eol=lf
mvnw.cmd text eol=crlf
.mvn/wrapper/maven-wrapper.properties text eol=lf

如果 mvnw 被 Windows 改成 CRLF,Linux 下可能会报:

1
bad interpreter: /bin/sh^M: no such file or directory

这个错误看起来像玄学,其实就是换行符在开派对。

7. 实战二:多模块项目添加 Maven Wrapper

假设你的项目是这样:

1
2
3
4
5
6
7
8
9
10
finance-parent/
├── pom.xml
├── finance-api/
│ └── pom.xml
├── finance-application/
│ └── pom.xml
├── finance-domain/
│ └── pom.xml
└── finance-infrastructure/
└── pom.xml

Maven Wrapper 应该放在聚合根项目,也就是最外层 finance-parent

1
2
3
4
5
cd finance-parent

mvn -N org.apache.maven.plugins:maven-wrapper-plugin:3.3.4:wrapper \
-Dmaven=3.9.16 \
-Dtype=only-script

这里加 -N 是为了只在当前根目录执行,不递归进入子模块。

执行构建:

1
./mvnw clean install

只构建某个模块及其依赖模块:

1
./mvnw -pl finance-application -am clean install

只构建某个模块,跳过测试:

1
./mvnw -pl finance-application -am clean install -DskipTests

建议在根目录 README 中写清楚:

1
2
3
4
5
6
7
## Build

This project uses Maven Wrapper. Please do not require contributors to install a specific Maven version manually.

```bash
./mvnw -B -ntp clean verify
```

8. 实战三:企业私服 Nexus / Artifactory 场景

企业项目里最常见的情况是:

  1. 依赖不能直接从 Maven Central 下载。
  2. 需要统一走公司 Nexus / Artifactory。
  3. 部分私有依赖需要账号密码或 token。
  4. CI 里不能暴露明文密码。

这时要区分两件事:

1
2
Wrapper 自己下载 Maven 发行包:看 distributionUrl / MVNW_REPOURL / MVNW_USERNAME / MVNW_PASSWORD
Maven 下载项目依赖:看 ~/.m2/settings.xml 里的 mirrors / servers / profiles

这两个经常被混在一起。混起来之后,排查构建问题就像在夜里找黑猫,关键猫还不一定在房间里。

8.1 Maven 依赖走公司私服

~/.m2/settings.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 https://maven.apache.org/xsd/settings-1.0.0.xsd">

<servers>
<server>
<id>company-maven</id>
<username>${env.MAVEN_REPO_USERNAME}</username>
<password>${env.MAVEN_REPO_PASSWORD}</password>
</server>
</servers>

<mirrors>
<mirror>
<id>company-maven</id>
<name>Company Maven Repository</name>
<url>https://nexus.example.com/repository/maven-public/</url>
<mirrorOf>*</mirrorOf>
</mirror>
</mirrors>

<profiles>
<profile>
<id>company-repo</id>
<repositories>
<repository>
<id>company-maven</id>
<url>https://nexus.example.com/repository/maven-public/</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>company-maven</id>
<url>https://nexus.example.com/repository/maven-public/</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</pluginRepository>
</pluginRepositories>
</profile>
</profiles>

<activeProfiles>
<activeProfile>company-repo</activeProfile>
</activeProfiles>
</settings>

关键点:

1
server.id 必须和 mirror.id / repository.id 对得上。

很多 401 问题不是密码错,而是 server.id 和仓库 id 没对上。密码在那里,Maven 却不知道该把它递给谁。

8.2 Wrapper 下载 Maven 发行包也走私服

方式一:直接改 distributionUrl

.mvn/wrapper/maven-wrapper.properties

1
2
distributionUrl=https://nexus.example.com/repository/maven-public/org/apache/maven/apache-maven/3.9.16/apache-maven-3.9.16-bin.zip
distributionType=only-script

方式二:保留默认 distributionUrl,运行时指定 MVNW_REPOURL

1
2
export MVNW_REPOURL=https://nexus.example.com/repository/maven-public
./mvnw clean verify

方式三:如果下载 Maven 发行包的位置需要 Basic Auth,可以设置:

1
2
3
export MVNW_USERNAME=your-username
export MVNW_PASSWORD=your-password-or-token
./mvnw clean verify

不要把账号密码直接写进 distributionUrl。虽然 Wrapper 支持这种方式,但企业项目里不建议这么做。仓库历史记录是没有“我只是临时写一下”的记忆删除功能的。

8.3 验证 effective settings

1
./mvnw -s ~/.m2/settings.xml help:effective-settings -Doutput=/tmp/effective-settings.xml

检查是否出现公司私服:

1
grep -n "company-maven\|nexus.example.com\|mirror" /tmp/effective-settings.xml

如果本地 mvn 能走私服,但 ./mvnw 不走,优先比较:

1
2
3
4
mvn -s ~/.m2/settings.xml help:effective-settings -Doutput=/tmp/mvn-settings.xml
./mvnw -s ~/.m2/settings.xml help:effective-settings -Doutput=/tmp/mvnw-settings.xml

diff /tmp/mvn-settings.xml /tmp/mvnw-settings.xml

如果 settings 一样但下载失败,继续看:

1
2
3
4
5
1. 公司 HTTPS 证书是否被当前 JDK 信任
2. server.id 是否和 mirror.id / repository.id 一致
3. CI 环境变量是否正确注入
4. Nexus / Artifactory 是否代理了 Maven 发行包路径
5. 是否被 .mvn/maven.config 或 MAVEN_ARGS 加了额外参数

9. 实战四:GitHub Actions 使用 Maven Wrapper

GitHub Actions 里推荐直接使用 ./mvnw,不要依赖 Runner 里预装的 Maven。

.github/workflows/maven.yml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
name: Java CI with Maven Wrapper

on:
push:
branches:
- main
- develop
pull_request:
branches:
- main
- develop

jobs:
build:
runs-on: ubuntu-latest

steps:
- name: Checkout source
uses: actions/checkout@v6

- name: Set up JDK 21
uses: actions/setup-java@v5
with:
distribution: temurin
java-version: '21'
cache: maven

- name: Ensure mvnw executable
run: chmod +x mvnw

- name: Build with Maven Wrapper
run: ./mvnw -B -ntp clean verify

说明:

配置 说明
actions/setup-java 安装指定 JDK
cache: maven 缓存 Maven 依赖,主要缓存 .m2/repository
./mvnw 使用项目指定 Maven 版本
-B -ntp CI 友好输出

如果是多模块项目,可以指定缓存依赖路径:

1
2
3
4
5
6
7
8
9
- name: Set up JDK 21
uses: actions/setup-java@v5
with:
distribution: temurin
java-version: '21'
cache: maven
cache-dependency-path: |
pom.xml
**/pom.xml

如果需要公司私服账号:

1
2
3
4
5
- name: Build with Maven Wrapper
env:
MAVEN_REPO_USERNAME: ${{ secrets.MAVEN_REPO_USERNAME }}
MAVEN_REPO_PASSWORD: ${{ secrets.MAVEN_REPO_PASSWORD }}
run: ./mvnw -B -ntp -s .github/settings.xml clean verify

.github/settings.xml 中引用环境变量:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0">
<servers>
<server>
<id>company-maven</id>
<username>${env.MAVEN_REPO_USERNAME}</username>
<password>${env.MAVEN_REPO_PASSWORD}</password>
</server>
</servers>
<mirrors>
<mirror>
<id>company-maven</id>
<url>https://nexus.example.com/repository/maven-public/</url>
<mirrorOf>*</mirrorOf>
</mirror>
</mirrors>
</settings>

注意:不要把真实账号密码提交到 .github/settings.xml

10. 实战五:GitLab CI 使用 Maven Wrapper

.gitlab-ci.yml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
stages:
- build
- test

variables:
MAVEN_OPTS: "-Dmaven.repo.local=$CI_PROJECT_DIR/.m2/repository"

cache:
key: "$CI_PROJECT_NAME-maven"
paths:
- .m2/repository
- .m2/wrapper/dists

build:
stage: build
image: eclipse-temurin:21
script:
- chmod +x mvnw
- ./mvnw -B -ntp -DskipTests clean package

test:
stage: test
image: eclipse-temurin:21
script:
- chmod +x mvnw
- ./mvnw -B -ntp test

这里缓存了两个目录:

1
2
.m2/repository       Maven 依赖缓存
.m2/wrapper/dists Maven Wrapper 下载的 Maven 发行包缓存

在 CI 容器里使用项目目录下的 .m2/repository,好处是缓存路径更可控,不依赖 Runner 用户目录。

11. 实战六:Jenkins Pipeline 使用 Maven Wrapper

Jenkinsfile

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
pipeline {
agent any

tools {
jdk 'jdk-21'
}

environment {
MAVEN_OPTS = '-Xmx2g'
}

stages {
stage('Checkout') {
steps {
checkout scm
}
}

stage('Build') {
steps {
sh 'chmod +x mvnw'
sh './mvnw -B -ntp clean package -DskipTests'
}
}

stage('Test') {
steps {
sh './mvnw -B -ntp test'
}
}
}

post {
always {
archiveArtifacts artifacts: '**/target/*.jar', fingerprint: true, allowEmptyArchive: true
junit '**/target/surefire-reports/*.xml'
}
}
}

如果 Jenkins 节点不能访问外网,建议:

1
2
3
4
1. distributionUrl 指向公司 Nexus / Artifactory
2. settings.xml 中配置 mirror
3. Jenkins Credentials 注入账号密码
4. Jenkins agent 镜像预置公司 CA 证书

12. IDEA 中如何使用 Maven Wrapper

IntelliJ IDEA 对 Maven Wrapper 支持比较自然:打开已有 Maven 项目时,如果发现 .mvn/wrapper/maven-wrapper.properties,可以将 Maven Wrapper 作为 Maven home path 使用。

推荐设置:

1
2
3
4
Settings / Preferences
-> Build, Execution, Deployment
-> Build Tools
-> Maven

建议:

1
2
3
4
5
6
7
8
9
10
11
Maven home path:
Use Maven Wrapper

User settings file:
Override -> /Users/你的用户名/.m2/settings.xml

Local repository:
/Users/你的用户名/.m2/repository

Use settings from .mvn/maven.config:
根据团队规范选择是否开启

如果 IDEA 没有自动识别 Wrapper,可以手动选择 Maven home path 为 Wrapper。

如果 IDEA Reload 走私服失败,优先检查:

1
2
3
4
5
1. IDEA Maven User settings file 是否指向正确 settings.xml
2. settings.xml 中 mirror 和 server id 是否一致
3. IDEA 使用的 JDK 是否信任公司私服 HTTPS 证书
4. 是否开启了 Work offline
5. 是否使用了项目里的 .mvn/maven.config

13. .mvn/maven.config 与 Wrapper 配合

Wrapper 只是 Maven 启动入口。Maven 的项目级命令行参数仍然可以放在:

1
.mvn/maven.config

例如:

1
2
3
4
-B
-ntp
--fail-at-end
-Dmaven.test.failure.ignore=false

以后执行:

1
./mvnw clean verify

就相当于自动带上这些参数。

从 Maven 3.9.0 开始,.mvn/maven.config 中每个参数应该单独一行,并且支持以 # 开头的注释。

示例:

1
2
3
4
5
6
7
8
# batch mode
-B

# do not print transfer progress
-ntp

# fail at end for multi-module build
--fail-at-end

注意:不要把本地个人路径写进 .mvn/maven.config

不推荐:

1
-s /Users/mario/.m2/settings.xml

因为别人电脑上没有这个路径。

推荐:

1
./mvnw -s ~/.m2/settings.xml clean verify

或者让每个人使用默认:

1
~/.m2/settings.xml

14. .mvn/jvm.config 与 Wrapper 配合

如果你希望项目构建时统一 JVM 参数,可以使用:

1
.mvn/jvm.config

例如:

1
2
3
4
-Xms512m
-Xmx2g
-Dfile.encoding=UTF-8
-Djava.awt.headless=true

然后执行:

1
./mvnw clean verify

Maven 启动时会读取这些 JVM 参数。

建议只放项目普适配置,不要放个人本机路径,也不要放敏感信息。

15. Maven Wrapper 与 JDK 版本

Maven Wrapper 只固定 Maven 版本,不固定 JDK 版本。

例如:

1
distributionUrl=...apache-maven-3.9.16-bin.zip

这只代表使用 Maven 3.9.16,不代表使用 JDK 21。

JDK 版本应该通过以下方式约束:

  1. README 明确说明。
  2. CI 明确指定 JDK。
  3. IDEA Project SDK 配置一致。
  4. Maven Toolchains 管理编译 JDK。
  5. maven-compiler-plugin 明确 release

推荐在 pom.xml 中配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<properties>
<java.version>21</java.version>
<maven.compiler.release>21</maven.compiler.release>
</properties>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.14.1</version>
<configuration>
<release>${maven.compiler.release}</release>
</configuration>
</plugin>
</plugins>
</build>

CI 中:

1
2
3
4
5
- uses: actions/setup-java@v5
with:
distribution: temurin
java-version: '21'
cache: maven

不要以为用了 Maven Wrapper,JDK 就自动对了。Wrapper 管 Maven,JDK 还得你自己管。一个管厨师,一个管厨房煤气,不能混为一谈。

16. 如何升级 Maven Wrapper 指定的 Maven 版本

假设当前是 Maven 3.9.9,希望升级到 3.9.16

方式一:重新执行插件。

1
2
3
mvn org.apache.maven.plugins:maven-wrapper-plugin:3.3.4:wrapper \
-Dmaven=3.9.16 \
-Dtype=only-script

方式二:直接修改 .mvn/wrapper/maven-wrapper.properties

1
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.16/apache-maven-3.9.16-bin.zip

然后验证:

1
2
./mvnw -v
./mvnw -B -ntp clean verify

建议升级流程:

1
2
3
4
5
6
7
1. 新建分支
2. 升级 distributionUrl
3. 本地执行 ./mvnw -v
4. 本地执行 ./mvnw clean verify
5. CI 全量跑通
6. 检查关键插件兼容性
7. 合并

对于生产项目,不建议直接切 Maven 4 预览版本。官方当前仍将 Maven 4.x 标记为 preview,不建议生产使用。企业项目稳一点,少一点刺激,生活会更美好。

17. Maven Wrapper 与 Maven 4

截至 2026-06-12,Apache Maven 下载页显示 Maven 3 当前推荐版本为 3.9.16,Maven 4 仍是 Preview 线。

如果你想试 Maven 4,可以生成:

1
2
3
mvn org.apache.maven.plugins:maven-wrapper-plugin:3.3.4:wrapper \
-Dmaven=4.0.0-rc-5 \
-Dtype=only-script

但建议只用于:

1
2
3
4
1. 技术预研
2. 插件兼容性验证
3. 新项目实验
4. CI 独立分支验证

不建议直接用于:

1
2
3
1. 生产发布构建
2. 老项目大规模迁移
3. 关键业务构建链路

18. Maven Wrapper 与 mvnd 的关系

你前面已经在调研 mvnd,这里顺带讲清楚它们的边界。

工具 定位 典型命令
Maven Wrapper 固定项目 Maven 版本 ./mvnw clean verify
Maven Daemon 加速 Maven 构建 mvnd clean verify

建议:

1
2
团队 README、CI、发布构建:使用 ./mvnw
个人本地频繁构建:使用 mvnd

不要强迫团队所有人都装 mvnd,但可以鼓励本地开发使用。

原因很简单:

1
2
mvnw 是项目自带能力,开箱即用。
mvnd 是个人开发环境优化,需要额外安装。

在团队标准化这件事上,mvnw 更适合作为基线。

19. Maven Wrapper 与 Maven Build Cache Extension 的关系

Maven Wrapper 固定 Maven 版本。

Maven Build Cache Extension 复用构建结果。

它们可以一起用。

项目结构:

1
2
3
4
5
6
7
8
9
project-root/
├── mvnw
├── mvnw.cmd
├── .mvn/
│ ├── wrapper/
│ │ └── maven-wrapper.properties
│ ├── extensions.xml
│ └── maven-build-cache-config.xml
└── pom.xml

.mvn/extensions.xml

1
2
3
4
5
6
7
8
9
<extensions xmlns="http://maven.apache.org/EXTENSIONS/1.1.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/EXTENSIONS/1.1.0 https://maven.apache.org/xsd/core-extensions-1.1.0.xsd">
<extension>
<groupId>org.apache.maven.extensions</groupId>
<artifactId>maven-build-cache-extension</artifactId>
<version>1.2.3</version>
</extension>
</extensions>

构建:

1
./mvnw -B -ntp clean verify

这时:

1
2
mvnw 负责使用指定 Maven 版本
Build Cache Extension 负责缓存构建产物

一个是“统一入口”,一个是“减少重复劳动”。

20. 推荐的企业项目目录规范

对于一个标准 Spring Boot 多模块项目,我建议这样组织:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
project-root/
├── .github/
│ └── workflows/
│ └── maven.yml
├── .mvn/
│ ├── wrapper/
│ │ └── maven-wrapper.properties
│ ├── maven.config
│ └── jvm.config
├── module-a/
│ └── pom.xml
├── module-b/
│ └── pom.xml
├── mvnw
├── mvnw.cmd
├── pom.xml
├── .gitattributes
├── .gitignore
└── README.md

.gitignore 不要忽略 Wrapper 文件。

推荐:

1
2
3
4
5
6
7
8
9
target/
.idea/
*.iml
.mvn/timing.properties

# 不要忽略下面这些:
# mvnw
# mvnw.cmd
# .mvn/wrapper/maven-wrapper.properties

.gitattributes

1
2
3
4
5
6
* text=auto
mvnw text eol=lf
mvnw.cmd text eol=crlf
*.sh text eol=lf
*.bat text eol=crlf
*.cmd text eol=crlf

README 构建说明:

1
2
3
4
5
6
7
8
9
10
11
12
13
## Build

This project uses Maven Wrapper. Use `./mvnw` instead of system `mvn`.

```bash
./mvnw -B -ntp clean verify
```

Windows:

```bat
mvnw.cmd -B -ntp clean verify
```

21. 常用命令速查

21.1 添加 Wrapper

1
mvn wrapper:wrapper

21.2 添加 Wrapper 并指定 Maven 版本

1
mvn wrapper:wrapper -Dmaven=3.9.16

21.3 添加 Wrapper 并指定类型

1
mvn wrapper:wrapper -Dmaven=3.9.16 -Dtype=only-script

21.4 使用指定插件版本生成 Wrapper

1
2
3
mvn org.apache.maven.plugins:maven-wrapper-plugin:3.3.4:wrapper \
-Dmaven=3.9.16 \
-Dtype=only-script

21.5 查看 Wrapper 使用的 Maven 版本

1
./mvnw -v

21.6 构建项目

1
./mvnw clean verify

21.7 CI 构建

1
./mvnw -B -ntp clean verify

21.8 使用指定 settings.xml

1
./mvnw -s ~/.m2/settings.xml clean verify

21.9 指定本地仓库目录

1
./mvnw -Dmaven.repo.local=/data/.m2/repository clean verify

21.10 打开 Wrapper 详细日志

1
MVNW_VERBOSE=true ./mvnw clean verify

Windows PowerShell:

1
2
$env:MVNW_VERBOSE="true"
.\mvnw.cmd clean verify

22. 常见问题排查

22.1 zsh: permission denied: ./mvnw

原因:mvnw 没有执行权限。

解决:

1
2
chmod +x mvnw
./mvnw -v

提交权限变化:

1
2
git update-index --chmod=+x mvnw
git commit -m "Fix mvnw executable permission"

22.2 bad interpreter: /bin/sh^M

原因:mvnw 被保存成了 CRLF 换行。

解决:

1
2
dos2unix mvnw
chmod +x mvnw

或者:

1
2
sed -i 's/\r$//' mvnw
chmod +x mvnw

再加 .gitattributes

1
2
mvnw text eol=lf
mvnw.cmd text eol=crlf

22.3 下载 Maven 发行包失败

常见原因:

1
2
3
4
5
1. 公司网络不能访问 Maven Central
2. 代理没有配置
3. Nexus / Artifactory 没代理 Maven 发行包路径
4. distributionUrl 配错
5. HTTPS 证书不被 JDK 信任

排查:

1
2
cat .mvn/wrapper/maven-wrapper.properties
MVNW_VERBOSE=true ./mvnw -v

企业内网建议:

1
2
export MVNW_REPOURL=https://nexus.example.com/repository/maven-public
./mvnw -v

或者直接改:

1
distributionUrl=https://nexus.example.com/repository/maven-public/org/apache/maven/apache-maven/3.9.16/apache-maven-3.9.16-bin.zip

22.4 依赖下载 401

原因通常不是 Wrapper,而是 Maven settings.xml

检查:

1
./mvnw -s ~/.m2/settings.xml help:effective-settings

重点看:

1
2
3
4
1. servers.server.id
2. mirrors.mirror.id
3. repositories.repository.id
4. distributionManagement.repository.id

server.id 要和 Maven 实际访问的仓库 id 对上。

22.5 IDEA 使用的 Maven 版本不对

检查:

1
2
3
4
5
Settings / Preferences
-> Build, Execution, Deployment
-> Build Tools
-> Maven
-> Maven home path

选择 Maven Wrapper。

然后 Reload Maven Project。

22.6 CI 中 ./mvnw: Permission denied

在 CI 中加:

1
- run: chmod +x mvnw

并在本地提交权限:

1
git update-index --chmod=+x mvnw

22.7 Wrapper 版本升级后仍使用旧 Maven

清理 Wrapper 缓存:

1
2
rm -rf ~/.m2/wrapper/dists
./mvnw -v

CI 中清理对应缓存 key,或者调整 cache key。

22.8 mvn 能构建,./mvnw 构建失败

排查顺序:

1
2
3
4
5
6
7
mvn -v
./mvnw -v

mvn help:effective-settings -Doutput=/tmp/mvn-settings.xml
./mvnw help:effective-settings -Doutput=/tmp/mvnw-settings.xml

diff /tmp/mvn-settings.xml /tmp/mvnw-settings.xml

常见原因:

1
2
3
4
5
1. Maven 版本不同
2. JDK 版本不同
3. MAVEN_OPTS / MAVEN_ARGS 不同
4. settings.xml 不同
5. .mvn/maven.config 被 Wrapper 读取后改变了行为

23. 安全建议

23.1 不要提交敏感信息

不要在这些文件中提交账号密码:

1
2
3
4
5
.mvn/wrapper/maven-wrapper.properties
.mvn/maven.config
pom.xml
README.md
.github/settings.xml

如果需要账号密码,使用:

1
2
3
4
5
环境变量
CI Secret
Jenkins Credentials
GitLab CI Variables
GitHub Actions Secrets

23.2 尽量加 checksum

建议对 Maven 发行包添加:

1
distributionSha256Sum=...

这能降低供应链攻击风险。

23.3 不要随意切 Maven 大版本

从 Maven 3.9.x 切到 Maven 4.x,不是“改个 URL”那么简单。

建议先检查:

1
2
3
4
5
6
1. 插件兼容性
2. 企业私服兼容性
3. CI 构建脚本
4. IDEA 导入表现
5. .mvn/maven.config 行为
6. release / deploy 流程

23.4 二进制文件入库要审慎

如果使用 bin 类型,会提交:

1
.mvn/wrapper/maven-wrapper.jar

这不一定有问题,但要符合团队安全规范。很多公司会要求二进制文件来源、校验值、许可证都能追踪。

24. 团队落地建议

我建议企业团队采用下面这套规则:

1
2
3
4
5
6
7
8
1. 所有 Maven 项目必须提交 Maven Wrapper
2. README 中统一写 ./mvnw 构建命令
3. CI/CD 必须使用 ./mvnw,不直接使用 mvn
4. Maven 版本由 .mvn/wrapper/maven-wrapper.properties 管理
5. JDK 版本由 CI、IDEA、Toolchains、compiler-plugin 管理
6. 私服账号只放 settings.xml / CI Secret,不进入项目仓库
7. mvnd 作为个人提速工具,不作为团队强依赖
8. 升级 Maven 版本必须走 PR 和 CI 验证

推荐 README 模板:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
## Development Environment

- JDK: 21
- Maven: managed by Maven Wrapper

## Build

Linux / macOS:

```bash
./mvnw -B -ntp clean verify
```

Windows:

```bat
mvnw.cmd -B -ntp clean verify
```

## Private Repository

This project uses the company Maven repository. Configure your local Maven settings at:

```text
~/.m2/settings.xml
```

Do not commit credentials into this repository.

25. 一套完整的工程化示例

下面给一套从 0 到 1 的完整示例。

25.1 创建项目

1
2
mkdir wrapper-demo
cd wrapper-demo

pom.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>cn.supermario.demo</groupId>
<artifactId>wrapper-demo</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>jar</packaging>

<properties>
<java.version>21</java.version>
<maven.compiler.release>21</maven.compiler.release>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.13.1</version>
<scope>test</scope>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.14.1</version>
<configuration>
<release>${maven.compiler.release}</release>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.5.3</version>
</plugin>
</plugins>
</build>
</project>

创建源码:

1
2
3
4
5
6
7
8
9
10
mkdir -p src/main/java/cn/supermario/demo
cat > src/main/java/cn/supermario/demo/App.java <<'EOF'
package cn.supermario.demo;

public class App {
public static String hello(String name) {
return "Hello, " + name;
}
}
EOF

创建测试:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
mkdir -p src/test/java/cn/supermario/demo
cat > src/test/java/cn/supermario/demo/AppTest.java <<'EOF'
package cn.supermario.demo;

import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertEquals;

class AppTest {
@Test
void shouldSayHello() {
assertEquals("Hello, Maven Wrapper", App.hello("Maven Wrapper"));
}
}
EOF

25.2 添加 Maven Wrapper

1
2
3
mvn org.apache.maven.plugins:maven-wrapper-plugin:3.3.4:wrapper \
-Dmaven=3.9.16 \
-Dtype=only-script

加权限:

1
chmod +x mvnw

验证:

1
2
./mvnw -v
./mvnw -B -ntp clean verify

25.3 增加项目级 Maven 配置

.mvn/maven.config

1
2
3
-B
-ntp
--fail-at-end

.mvn/jvm.config

1
2
-Xmx1g
-Dfile.encoding=UTF-8

再次构建:

1
./mvnw clean verify

25.4 增加 Git 规范

.gitattributes

1
2
3
4
5
6
* text=auto
mvnw text eol=lf
mvnw.cmd text eol=crlf
*.sh text eol=lf
*.bat text eol=crlf
*.cmd text eol=crlf

.gitignore

1
2
3
4
target/
.idea/
*.iml
.DS_Store

提交:

1
2
3
git init
git add .
git commit -m "Initialize Maven Wrapper demo"

25.5 新同事使用

新同事只需要:

1
2
3
git clone <repo-url>
cd wrapper-demo
./mvnw clean verify

不需要先问:

1
你们这个项目 Maven 用几啊?

这个问题由项目自己回答。

26. 最佳实践清单

项目 建议
是否使用 Maven Wrapper 团队项目建议必须使用
Maven 版本 使用当前 Maven 3 推荐版本,谨慎使用 Maven 4 Preview
Wrapper 类型 默认 only-script
是否提交 mvnw
是否提交 mvnw.cmd
是否提交 maven-wrapper.properties
是否提交账号密码
CI 是否使用 Wrapper
IDEA 是否使用 Wrapper 推荐使用
私服配置 settings.xml,不要写死在项目里
Maven 发行包下载 内网用 distributionUrlMVNW_REPOURL 指向私服代理
安全校验 建议配置 distributionSha256Sum
本地加速 可搭配 mvnd,但不强制团队安装

结论

Maven Wrapper 的价值不在于多高级,而在于它足够朴素、足够稳定、足够适合作为团队构建的共同入口。

它解决的是一个非常实际的问题:

这个项目到底应该用哪个 Maven 构建?

没有 Wrapper 时,这个答案散落在每个人电脑里、CI 镜像里、README 里、甚至老员工记忆里。

有了 Wrapper 后,这个答案就在项目里。

对于企业 Java 项目,我的建议很明确:

1
2
3
CI/CD、README、团队标准命令统一使用 ./mvnw。
本地开发想更快,可以额外使用 mvnd。
构建产物想复用,可以再接 Maven Build Cache Extension。

先统一,再提速。工程化不是把工具堆满,而是让每个工具站在正确的位置。

参考资料

  1. Apache Maven Wrapper 官方文档:https://maven.apache.org/tools/wrapper/
  2. Apache Maven Wrapper Plugin:https://maven.apache.org/tools/wrapper/maven-wrapper-plugin/
  3. wrapper:wrapper Goal 参数说明:https://maven.apache.org/tools/wrapper/maven-wrapper-plugin/wrapper-mojo.html
  4. Maven 配置指南:https://maven.apache.org/guides/mini/guide-configuring-maven.html
  5. Maven Settings Reference:https://maven.apache.org/settings.html
  6. Maven Mirror Settings:https://maven.apache.org/guides/mini/guide-mirror-settings.html
  7. Apache Maven 下载页:https://maven.apache.org/download.cgi
  8. GitHub Actions setup-java:https://github.com/actions/setup-java
  9. IntelliJ IDEA Maven 文档:https://www.jetbrains.com/help/idea/maven.html

启示录

富贵岂由人,时会高志须酬。

能成功于千载者,必以近察远。


Maven Wrapper 深入讲解与实战:让团队构建环境真正一致
https://allendericdalexander.github.io/2026/06/12/scm/maven-wrapper-deep-dive-blog/
作者
AtLuoFu
发布于
2026年6月12日
许可协议