Maven 4 要来了:15 年后,Java 构建工具迎来“彻底重构“

大家好,我是Java1234_小锋老师。

一、为什么 Maven 4 等了这么久?

如果你用 Java 做项目,Maven 大概率不陌生。

2004 年 Maven 2 发布,2010 年 Maven 3 上线------之后十多年,社区一直在 3.x 小版本上迭代。不是团队偷懒,而是 POM 文件背负了太多东西:既要描述"怎么构建",又要告诉下游"怎么依赖我"。

一旦改 POM 格式,Maven Central、IDE、Gradle 互操作、各类插件都要跟着动。于是 POM 4.0.0 的语法几乎被"冻住"了,很多 2005 年就提过的改进(比如自动推断父 POM 版本)一直拖到现在。

Maven 4 的思路很直白:把"构建用的 POM"和"给别人用的 POM"分开。构建时可以大胆进化,发布到仓库时仍保持兼容。这才是标题里"彻底重构"的真正含义------不是换皮,而是把底层架构理顺了。


二、Maven 4 现在走到哪一步了?

截至 2026 年 7 月,Maven 4 已发布多个 RC(Release Candidate)版本,最新为 4.0.0-rc-5(2025-11-13)。官方仍标注为测试用途,生产环境建议等 GA 正式版。

几个硬性变化需要提前知道:

项目 Maven 3.x Maven 4
运行 Maven 本身 Java 8+ Java 17+
编译项目代码 自行配置 仍可编译 Java 8/11/17 等
POM 模型 4.0.0 构建可用 4.1.0
依赖解析 Resolver 1.x Resolver 2.0

注意:Java 17 只是运行 Maven 的要求,不代表你的项目必须升到 Java 17。老项目照样可以用 Toolchains 指定编译 JDK。


三、核心变化:Build POM 与 Consumer POM 分离

这是 Maven 4 最重要的架构调整。

  • Build POM:存在 Git 仓库里,包含插件配置、属性、父 POM 引用等完整信息。
  • Consumer POM:发布到 Maven Central 的精简版,只保留下游真正需要的依赖信息。

构建完成后,Maven 4 会自动从 Build POM 生成 Consumer POM。Consumer POM 会去掉 parent 引用(继承内容已内联)、去掉插件配置、只保留实际用到的依赖。

构建与发布流程

#mermaid-svg-LiaY2IJfq2RIuspR{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-LiaY2IJfq2RIuspR .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-LiaY2IJfq2RIuspR .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-LiaY2IJfq2RIuspR .error-icon{fill:#552222;}#mermaid-svg-LiaY2IJfq2RIuspR .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-LiaY2IJfq2RIuspR .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-LiaY2IJfq2RIuspR .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-LiaY2IJfq2RIuspR .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-LiaY2IJfq2RIuspR .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-LiaY2IJfq2RIuspR .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-LiaY2IJfq2RIuspR .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-LiaY2IJfq2RIuspR .marker{fill:#333333;stroke:#333333;}#mermaid-svg-LiaY2IJfq2RIuspR .marker.cross{stroke:#333333;}#mermaid-svg-LiaY2IJfq2RIuspR svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-LiaY2IJfq2RIuspR p{margin:0;}#mermaid-svg-LiaY2IJfq2RIuspR .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-LiaY2IJfq2RIuspR .cluster-label text{fill:#333;}#mermaid-svg-LiaY2IJfq2RIuspR .cluster-label span{color:#333;}#mermaid-svg-LiaY2IJfq2RIuspR .cluster-label span p{background-color:transparent;}#mermaid-svg-LiaY2IJfq2RIuspR .label text,#mermaid-svg-LiaY2IJfq2RIuspR span{fill:#333;color:#333;}#mermaid-svg-LiaY2IJfq2RIuspR .node rect,#mermaid-svg-LiaY2IJfq2RIuspR .node circle,#mermaid-svg-LiaY2IJfq2RIuspR .node ellipse,#mermaid-svg-LiaY2IJfq2RIuspR .node polygon,#mermaid-svg-LiaY2IJfq2RIuspR .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-LiaY2IJfq2RIuspR .rough-node .label text,#mermaid-svg-LiaY2IJfq2RIuspR .node .label text,#mermaid-svg-LiaY2IJfq2RIuspR .image-shape .label,#mermaid-svg-LiaY2IJfq2RIuspR .icon-shape .label{text-anchor:middle;}#mermaid-svg-LiaY2IJfq2RIuspR .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-LiaY2IJfq2RIuspR .rough-node .label,#mermaid-svg-LiaY2IJfq2RIuspR .node .label,#mermaid-svg-LiaY2IJfq2RIuspR .image-shape .label,#mermaid-svg-LiaY2IJfq2RIuspR .icon-shape .label{text-align:center;}#mermaid-svg-LiaY2IJfq2RIuspR .node.clickable{cursor:pointer;}#mermaid-svg-LiaY2IJfq2RIuspR .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-LiaY2IJfq2RIuspR .arrowheadPath{fill:#333333;}#mermaid-svg-LiaY2IJfq2RIuspR .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-LiaY2IJfq2RIuspR .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-LiaY2IJfq2RIuspR .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-LiaY2IJfq2RIuspR .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-LiaY2IJfq2RIuspR .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-LiaY2IJfq2RIuspR .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-LiaY2IJfq2RIuspR .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-LiaY2IJfq2RIuspR .cluster text{fill:#333;}#mermaid-svg-LiaY2IJfq2RIuspR .cluster span{color:#333;}#mermaid-svg-LiaY2IJfq2RIuspR 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-LiaY2IJfq2RIuspR .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-LiaY2IJfq2RIuspR rect.text{fill:none;stroke-width:0;}#mermaid-svg-LiaY2IJfq2RIuspR .icon-shape,#mermaid-svg-LiaY2IJfq2RIuspR .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-LiaY2IJfq2RIuspR .icon-shape p,#mermaid-svg-LiaY2IJfq2RIuspR .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-LiaY2IJfq2RIuspR .icon-shape .label rect,#mermaid-svg-LiaY2IJfq2RIuspR .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-LiaY2IJfq2RIuspR .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-LiaY2IJfq2RIuspR .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-LiaY2IJfq2RIuspR :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 是

开发者提交 Build POM
Maven 4 本地构建
执行 deploy?
自动生成 Consumer POM
上传到 Maven Central
本地仓库保留构建产物
其他项目下载 Consumer POM 解析依赖

如何开启 Consumer POM 发布?

在 rc-5 中,Consumer POM 扁平化默认关闭,需要显式开启:

xml 复制代码
<!-- .mvn/maven-user.properties -->
maven.consumer.pom.flatten=true

或在命令行传递:

bash 复制代码
mvn deploy -Dmaven.consumer.pom.flatten=true

四、POM 4.1.0:少写重复配置

升级到 POM 模型 4.1.0 后,很多"复制粘贴式"的配置可以删掉了。Maven 3 的 4.0.0 POM 仍然能正常构建,不升级也不影响。

1. 父 POM 版本自动推断

2005 年的老需求,Maven 4 终于内置了。子模块不必再写 <version>

xml 复制代码
<project xmlns="http://maven.apache.org/POM/4.1.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.1.0
         https://maven.apache.org/xsd/maven-4.1.0.xsd">

  <!-- 省略 version,Maven 自动从父目录推断 -->
  <parent>
    <groupId>com.example</groupId>
    <artifactId>my-app-parent</artifactId>
  </parent>

  <artifactId>my-service</artifactId>

  <dependencies>
    <!-- 同仓库子模块依赖也可省略 version -->
    <dependency>
      <groupId>com.example</groupId>
      <artifactId>my-common</artifactId>
    </dependency>
  </dependencies>
</project>

2. 子模块自动发现

父 POM 使用 pom 打包,且没有手动写 <subprojects> 时,Maven 4 会自动扫描子目录里的 pom.xml

xml 复制代码
<project xmlns="http://maven.apache.org/POM/4.1.0">
  <modelVersion>4.1.0</modelVersion>
  <groupId>com.example</groupId>
  <artifactId>my-app-parent</artifactId>
  <version>1.0.0-SNAPSHOT</version>
  <packaging>pom</packaging>

  <!-- 不写 subprojects,子目录有 pom.xml 就会自动加入构建 -->
</project>

3. CI 友好版本号,不再需要 Flatten 插件

Maven 3 时代常用 ${revision} 配合 flatten-maven-plugin。Maven 4 内置完整支持:

xml 复制代码
<groupId>com.example</groupId>
<artifactId>my-app</artifactId>
<version>${revision}</version>
bash 复制代码
# 在 CI 流水线中指定版本
mvn verify -Drevision=1.2.0

或在 .mvn/maven.config 中固定:

复制代码
-Drevision=1.0.0-SNAPSHOT

4. 新的 BOM 打包类型

BOM(Bill of Materials)有了专属 packaging 类型,和 parent POM 职责分得更清楚:

xml 复制代码
<project xmlns="http://maven.apache.org/POM/4.1.0">
  <modelVersion>4.1.0</modelVersion>
  <groupId>com.example</groupId>
  <artifactId>my-app-bom</artifactId>
  <version>1.0.0</version>
  <packaging>bom</packaging>

  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-dependencies</artifactId>
        <version>3.4.0</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
    </dependencies>
  </dependencyManagement>
</project>

5. 多源码目录,告别 Build Helper 插件

xml 复制代码
<build>
  <sources>
    <source>
      <scope>main</scope>
      <directory>src/main/java</directory>
    </source>
    <source>
      <scope>main</scope>
      <directory>src/main/kotlin</directory>
    </source>
    <source>
      <scope>test</scope>
      <directory>src/test/java</directory>
    </source>
  </sources>
</build>

五、新工具与日常体验升级

Maven Upgrade Tool(mvnup)

官方提供的迁移助手,先检查、再自动修复:

bash 复制代码
# 检查项目与 Maven 4 的兼容问题
mvnup check

# 自动应用推荐的 POM 修复
mvnup apply

Maven Shell(mvnsh)

类似 REPL 的交互式 Shell,改完代码不用反复敲完整命令:

bash 复制代码
mvnsh
# 进入交互模式后
mvn> compile
mvn> test -pl my-service
mvn> exit

构建失败后一键续跑

多模块项目构建失败后,Maven 4 的 -r--resume)更聪明------会自动从失败模块续跑,并跳过已成功构建的模块:

bash 复制代码
# 首次全量构建
mvn verify

# 修复代码后,从失败处继续
mvn verify -r

迁移决策流程

#mermaid-svg-QRwHOOlBQUN5eZNH{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-QRwHOOlBQUN5eZNH .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-QRwHOOlBQUN5eZNH .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-QRwHOOlBQUN5eZNH .error-icon{fill:#552222;}#mermaid-svg-QRwHOOlBQUN5eZNH .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-QRwHOOlBQUN5eZNH .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-QRwHOOlBQUN5eZNH .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-QRwHOOlBQUN5eZNH .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-QRwHOOlBQUN5eZNH .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-QRwHOOlBQUN5eZNH .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-QRwHOOlBQUN5eZNH .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-QRwHOOlBQUN5eZNH .marker{fill:#333333;stroke:#333333;}#mermaid-svg-QRwHOOlBQUN5eZNH .marker.cross{stroke:#333333;}#mermaid-svg-QRwHOOlBQUN5eZNH svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-QRwHOOlBQUN5eZNH p{margin:0;}#mermaid-svg-QRwHOOlBQUN5eZNH .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-QRwHOOlBQUN5eZNH .cluster-label text{fill:#333;}#mermaid-svg-QRwHOOlBQUN5eZNH .cluster-label span{color:#333;}#mermaid-svg-QRwHOOlBQUN5eZNH .cluster-label span p{background-color:transparent;}#mermaid-svg-QRwHOOlBQUN5eZNH .label text,#mermaid-svg-QRwHOOlBQUN5eZNH span{fill:#333;color:#333;}#mermaid-svg-QRwHOOlBQUN5eZNH .node rect,#mermaid-svg-QRwHOOlBQUN5eZNH .node circle,#mermaid-svg-QRwHOOlBQUN5eZNH .node ellipse,#mermaid-svg-QRwHOOlBQUN5eZNH .node polygon,#mermaid-svg-QRwHOOlBQUN5eZNH .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-QRwHOOlBQUN5eZNH .rough-node .label text,#mermaid-svg-QRwHOOlBQUN5eZNH .node .label text,#mermaid-svg-QRwHOOlBQUN5eZNH .image-shape .label,#mermaid-svg-QRwHOOlBQUN5eZNH .icon-shape .label{text-anchor:middle;}#mermaid-svg-QRwHOOlBQUN5eZNH .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-QRwHOOlBQUN5eZNH .rough-node .label,#mermaid-svg-QRwHOOlBQUN5eZNH .node .label,#mermaid-svg-QRwHOOlBQUN5eZNH .image-shape .label,#mermaid-svg-QRwHOOlBQUN5eZNH .icon-shape .label{text-align:center;}#mermaid-svg-QRwHOOlBQUN5eZNH .node.clickable{cursor:pointer;}#mermaid-svg-QRwHOOlBQUN5eZNH .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-QRwHOOlBQUN5eZNH .arrowheadPath{fill:#333333;}#mermaid-svg-QRwHOOlBQUN5eZNH .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-QRwHOOlBQUN5eZNH .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-QRwHOOlBQUN5eZNH .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-QRwHOOlBQUN5eZNH .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-QRwHOOlBQUN5eZNH .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-QRwHOOlBQUN5eZNH .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-QRwHOOlBQUN5eZNH .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-QRwHOOlBQUN5eZNH .cluster text{fill:#333;}#mermaid-svg-QRwHOOlBQUN5eZNH .cluster span{color:#333;}#mermaid-svg-QRwHOOlBQUN5eZNH 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-QRwHOOlBQUN5eZNH .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-QRwHOOlBQUN5eZNH rect.text{fill:none;stroke-width:0;}#mermaid-svg-QRwHOOlBQUN5eZNH .icon-shape,#mermaid-svg-QRwHOOlBQUN5eZNH .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-QRwHOOlBQUN5eZNH .icon-shape p,#mermaid-svg-QRwHOOlBQUN5eZNH .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-QRwHOOlBQUN5eZNH .icon-shape .label rect,#mermaid-svg-QRwHOOlBQUN5eZNH .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-QRwHOOlBQUN5eZNH .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-QRwHOOlBQUN5eZNH .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-QRwHOOlBQUN5eZNH :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 否





准备迁移 Maven 4
本机 Java >= 17?
安装 JDK 17 作为 Maven 运行环境
下载 Maven 4.0.0-rc-5
运行 mvnup check
有问题?
mvnup apply 或手动升级插件
mvn verify 验证构建
构建成功?
逐步在 CI 中切换
加 -e 参数查看堆栈, 提 Issue 或回退


六、从 Maven 3 迁移,可以怎么做?

不必一步到位。比较稳妥的路径:

  1. 本地先试 :装 Maven 4 RC + JDK 17,跑 mvnup check
  2. 升级插件:enforcer、shade、remote-resources 等插件升到最新版。
  3. 固定插件版本:Maven 4 的 Super POM 默认插件版本有变化,建议在 POM 里显式写死版本,避免"没改代码构建行为却变了"。
  4. CI 并行验证:保留 Maven 3 流水线,新增一条 Maven 4 试验线。
  5. 等 GA 再全面切换:RC 阶段适合尝鲜和反馈,生产环境建议等正式版。

一个最小验证示例:

bash 复制代码
# 下载并解压 Maven 4
curl -L -O https://archive.apache.org/dist/maven/maven-4/4.0.0-rc-5/binaries/apache-maven-4.0.0-rc-5-bin.tar.gz
tar -xzf apache-maven-4.0.0-rc-5-bin.tar.gz

# 指定 Maven 4 运行(不影响系统默认 Maven 3)
/path/to/apache-maven-4.0.0-rc-5/bin/mvn -version

# 在项目目录检查兼容性
/path/to/apache-maven-4.0.0-rc-5/bin/mvnup check

七、写在最后

Maven 4 不是简单地把版本号从 3 改成 4。

它用 Build POM / Consumer POM 分离 解开了 POM 格式冻结的死结,用 POM 4.1.0 把十多年来社区的呼声落到了代码里,还带来了 mvnup、mvnsh、Resolver 2.0 等实打实的体验提升。

如果你现在项目跑在 Maven 3 上很稳,不必焦虑------Maven 3 还会维护一段时间。但如果你正在维护大型多模块项目、受够了重复的版本号维护、或者在 CI 里被 flatten 插件折腾过,现在正是关注 Maven 4 的好时候。

GA 正式版应该不远了。在那之前,不妨拿一个非核心项目跑通 mvnup check,亲身感受一下这次"15 年后的彻底重构"到底改了什么。

相关推荐
霸道流氓气质1 小时前
Java 工程师 AI 智能体学习路线 · 阶段 1:AI / LLM 基础认知 详解
java·人工智能·学习
Drgfd1 小时前
高压快充普及重构用车生态:补能格局洗牌,重新定义新能源车产品力
重构
JerrySir2 小时前
`spring.threads.virtual.enabled=true`:用三类负载定位等待、争用与拒绝
java·spring boot
尚早立志2 小时前
Spring Boot 之 BeanDefinitionLoader 详解
java·spring boot·后端
月光有害2 小时前
DDD 核心概念梳理:从领域模型到领域事件
java·ddd
snow@li2 小时前
Java:后端项目会有一个类似前端node_modules的目录吗 / jar包在本地仓库 ~/.m2/repository 中按版本共存
java·开发语言·前端
济*沧*海2 小时前
创建springboot项目时会出现注释乱码情况
java·spring boot·后端
geovindu2 小时前
java: Builder Pattern
java·开发语言·后端·设计模式·建造者模式·生成器模式
卓怡学长2 小时前
w268基于springboot + vue 物流系统
java·数据库·vue.js·spring boot·spring·intellij-idea