欢迎你来读这篇博客,这篇博客主要是关于 Maven Wrapper 的完整讲解与工程化落地。
Maven Wrapper 看起来只是多了两个脚本:mvnw 和 mvnw.cmd,但它真正解决的是团队协作里非常现实的问题:同一个项目,到底应该用哪个 Maven 版本构建 。
很多构建问题并不是代码错了,而是 A 同事本地 Maven 3.6,B 同事本地 Maven 3.9,CI 又是另一个版本。最后大家一起围着构建日志开会,场面非常热闹,但没有生产力。
Maven Wrapper 的价值就是:把 Maven 版本和启动方式收进项目本身,让开发机、IDE、CI/CD、临时构建环境尽量使用同一套 Maven 入口。
序言 在 Java 项目里,我们通常会直接执行:
这条命令默认使用的是当前机器 PATH 里找到的 Maven 。这意味着项目构建结果会受到本机 Maven 安装版本的影响。
对于个人项目,这通常没什么问题。但对于团队项目、企业项目、CI/CD、开源项目来说,这就会带来几个典型问题:
新同事拉代码后,不知道该安装哪个 Maven 版本。
本地构建通过,CI 构建失败。
CI 构建通过,本地 IDEA Reload Maven Project 报错。
Maven 3.8、3.9、4.x 对部分配置、插件校验、.mvn/maven.config 解析存在差异。
公司私服、代理、内网环境下,Maven 下载入口混乱。
Maven Wrapper 的核心目标不是让 Maven 跑得更快,而是让 Maven 跑得更一致 。
一句话总结:
mvn 是使用本机 Maven;mvnw 是使用项目指定的 Maven。
正文 1. Maven Wrapper 是什么 Maven Wrapper 是一组可以提交到项目仓库里的 Maven 启动脚本。项目中加入 Maven Wrapper 后,使用者不需要提前在本机安装指定版本的 Maven,而是直接执行项目自带的脚本:
Windows 下执行:
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 会生成哪些文件 在项目根目录执行:
或者指定 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.jar 或 MavenWrapperDownloader.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 源码
视团队规范
最关键的是:mvnw、mvnw.cmd、.mvn/wrapper/maven-wrapper.properties 应该提交到仓库。
不提交这几个文件,就像给别人发车钥匙但忘了发车,礼貌但没用。
4. maven-wrapper.properties 详解 一个常见的 .mvn/wrapper/maven-wrapper.properties 可能长这样:
1 2 3 4 5 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-script 比 bin 更清爽。
如果构建环境没有 curl、wget、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 缓存中,例如:
如果你希望改变 Maven 发行包安装基础目录,可以设置:
1 export MAVEN_USER_HOME=/data/maven-user-home
然后执行:
这在 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:
验证:
正常情况下会看到 Maven 3.9.16。
6.3 用 Wrapper 构建项目
跳过测试:
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 -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 场景 企业项目里最常见的情况是:
依赖不能直接从 Maven Central 下载。
需要统一走公司 Nexus / Artifactory。
部分私有依赖需要账号密码或 token。
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-usernameexport 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 2 3 4 -B -ntp --fail-at-end -Dmaven.test.failure.ignore=false
以后执行:
就相当于自动带上这些参数。
从 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
或者让每个人使用默认:
14. .mvn/jvm.config 与 Wrapper 配合 如果你希望项目构建时统一 JVM 参数,可以使用:
例如:
1 2 3 4 -Xms512m -Xmx2g -Dfile.encoding=UTF-8 -Djava.awt.headless=true
然后执行:
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 版本应该通过以下方式约束:
README 明确说明。
CI 明确指定 JDK。
IDEA Project SDK 配置一致。
Maven Toolchains 管理编译 JDK。
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
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 版本
21.6 构建项目
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 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 mvnwchmod +x mvnw
或者:
1 2 sed -i 's/\r$//' mvnwchmod +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 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-democd 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/democat > 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/democat > 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 2 ./mvnw -v ./mvnw -B -ntp clean verify
25.3 增加项目级 Maven 配置 .mvn/maven.config:
.mvn/jvm.config:
1 2 -Xmx1g -Dfile.encoding=UTF-8
再次构建:
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
不需要先问:
这个问题由项目自己回答。
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 发行包下载
内网用 distributionUrl 或 MVNW_REPOURL 指向私服代理
安全校验
建议配置 distributionSha256Sum
本地加速
可搭配 mvnd,但不强制团队安装
结论 Maven Wrapper 的价值不在于多高级,而在于它足够朴素、足够稳定、足够适合作为团队构建的共同入口。
它解决的是一个非常实际的问题:
这个项目到底应该用哪个 Maven 构建?
没有 Wrapper 时,这个答案散落在每个人电脑里、CI 镜像里、README 里、甚至老员工记忆里。
有了 Wrapper 后,这个答案就在项目里。
对于企业 Java 项目,我的建议很明确:
1 2 3 CI/CD、README、团队标准命令统一使用 ./mvnw。 本地开发想更快,可以额外使用 mvnd。 构建产物想复用,可以再接 Maven Build Cache Extension。
先统一,再提速。工程化不是把工具堆满,而是让每个工具站在正确的位置。
参考资料
Apache Maven Wrapper 官方文档:https://maven.apache.org/tools/wrapper/
Apache Maven Wrapper Plugin:https://maven.apache.org/tools/wrapper/maven-wrapper-plugin/
wrapper:wrapper Goal 参数说明:https://maven.apache.org/tools/wrapper/maven-wrapper-plugin/wrapper-mojo.html
Maven 配置指南:https://maven.apache.org/guides/mini/guide-configuring-maven.html
Maven Settings Reference:https://maven.apache.org/settings.html
Maven Mirror Settings:https://maven.apache.org/guides/mini/guide-mirror-settings.html
Apache Maven 下载页:https://maven.apache.org/download.cgi
GitHub Actions setup-java:https://github.com/actions/setup-java
IntelliJ IDEA Maven 文档:https://www.jetbrains.com/help/idea/maven.html
启示录 富贵岂由人,时会高志须酬。
能成功于千载者,必以近察远。