← 返回题目列表

Maven 常用的插件有哪些?compiler、surefire、shade、assembly 各是干什么的?

中等 第 21 / 23 题 更新于 2026/07/28
Maven插件compiler-pluginsurefireshade

简化版

Maven 本身只是一个「插件执行框架」——它的所有实际工作(编译、测试、打包)都是由「插件(plugin)」完成的,插件的「目标(goal)」绑定到构建生命周期的各个阶段。常用插件:maven-compiler-plugin——编译 Java 代码(配置 JDK 版本 source/target 或 release,控制用哪个 Java 版本编译);maven-surefire-plugin——运行单元测试mvn test 阶段执行,控制测试哪些、跳过测试、生成报告);maven-failsafe-plugin——运行集成测试(和 surefire 分开,集成测试在 integration-test 阶段);maven-jar-plugin——打普通 jar 包;maven-shade-plugin——打「可执行的 fat jar / uber jar」(把项目 + 所有依赖打进一个 jar,能 java -jar 直接运行,还能重命名依赖包避免冲突);maven-assembly-plugin——按「装配描述」打各种分发包(jar-with-dependencies、tar.gz 等);spring-boot-maven-plugin——Spring Boot 专用打可执行 jar。核心记忆:compiler 编译(管 JDK 版本)、surefire 跑单元测试、failsafe 跑集成测试、shade/assembly/spring-boot 打可执行 fat jar;Maven 是插件框架,所有工作靠插件的 goal 绑定生命周期完成。

详细版

常用 Maven 插件

插件作用绑定阶段
maven-compiler-plugin编译(JDK 版本)compile
maven-surefire-plugin单元测试test
maven-failsafe-plugin集成测试integration-test
maven-jar-plugin打普通 jarpackage
maven-shade-plugin打 fat jar(含依赖,可重定位)package
maven-assembly-plugin打各种分发包package
spring-boot-maven-plugin打 Spring Boot 可执行 jarpackage
maven-resources-plugin处理资源文件process-resources
<build>
  <plugins>
    <!-- 编译插件:指定 JDK 版本 -->
    <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-compiler-plugin</artifactId>
      <configuration>
        <release>17</release>   <!-- 或 source/target 17 -->
      </configuration>
    </plugin>

    <!-- surefire:单元测试 -->
    <plugin>
      <artifactId>maven-surefire-plugin</artifactId>
      <configuration>
        <skipTests>false</skipTests>       <!-- 是否跳过测试 -->
        <includes><include>**/*Test.java</include></includes>
      </configuration>
    </plugin>

    <!-- shade:打 fat jar(含所有依赖,可执行)-->
    <plugin>
      <artifactId>maven-shade-plugin</artifactId>
      <executions>
        <execution>
          <phase>package</phase>
          <goals><goal>shade</goal></goals>
          <configuration>
            <transformers>
              <transformer implementation="...ManifestResourceTransformer">
                <mainClass>com.example.Main</mainClass>   <!-- 指定主类 -->
              </transformer>
            </transformers>
          </configuration>
        </execution>
      </executions>
    </plugin>
  </plugins>
</build>

⚠️ 理解 Maven 的关键是「Maven 本身几乎什么都不做,所有工作都是插件干的」——mvn compilemvn testmvn package 触发的是绑定到这些阶段的插件的 goal。Maven 的构建生命周期(validate → compile → test → package → verify → install → deploy)只是「阶段的骨架」,每个阶段执行什么,取决于「绑定到这个阶段的插件目标(goal)」——mvn compile 执行 maven-compiler-plugincompile goal、mvn test 执行 maven-surefire-plugintest goal、mvn package 执行打包插件的 goal。所以理解 Maven = 理解「生命周期阶段 + 插件 goal 绑定」。几个高频区分:surefire(单元测试)vs failsafe(集成测试)——分开是因为集成测试慢、可能失败但不该中断构建(failsafe 的 goal 让集成测试失败不立即停);shade vs assembly vs spring-boot——都能打 fat jar,shade 还能「重定位依赖」(把依赖的包名改掉,避免和别的库的同名类冲突,常用于写库时避免依赖冲突)、spring-boot 用特殊的嵌套 jar 结构(Spring Boot 应用用它)、assembly 最灵活(按描述文件打各种格式)。

完整版教学

一、Maven 是插件框架

先理解 Maven 的本质——插件框架:

Maven 的本质:一个"插件执行框架"
  Maven 核心几乎什么都不做
  → 所有实际工作(编译、测试、打包)都是"插件"干的

生命周期(Lifecycle)+ 阶段(Phase):
  Maven 有构建生命周期,由一系列阶段组成:
    validate → compile → test → package → verify → install → deploy
  → 阶段是"骨架"(顺序执行的步骤)

插件目标(Plugin Goal)绑定到阶段:
  每个阶段执行什么 = "绑定到这个阶段的插件 goal"
  compile 阶段 → maven-compiler-plugin:compile(编译)
  test 阶段 → maven-surefire-plugin:test(跑测试)
  package 阶段 → maven-jar-plugin:jar(打包)
  → 阶段 + 插件 goal 绑定 = 实际执行的工作

执行命令:
  mvn compile → 执行到 compile 阶段(触发绑定的插件 goal)
  mvn test → 执行到 test 阶段
  mvn package → 执行到 package 阶段
  → 执行某阶段 = 执行"它及之前所有阶段"绑定的 goal

所以 Maven = 插件框架(生命周期阶段 + 插件 goal 绑定)
  理解 Maven = 理解"阶段 + 插件"

Maven 的本质是「插件执行框架」——核心几乎什么都不做、所有实际工作(编译/测试/打包)都是插件干的生命周期(Lifecycle)+ 阶段(Phase)validate→compile→test→package→verify→install→deploy(阶段是骨架)。插件目标(Goal)绑定到阶段:每个阶段执行什么 = 绑定到它的插件 goal(compile→compiler-plugin、test→surefire、package→jar-plugin)。执行命令:mvn compile/test/package 执行到某阶段(触发绑定的 goal)。理解「Maven 是插件框架(核心什么都不做,工作靠插件);生命周期阶段(validate→compile→test→package→install→deploy 骨架)+插件 goal 绑定到阶段;mvn compile 执行到该阶段触发绑定 goal;理解 Maven=理解阶段+插件」,就理解了 Maven 是插件框架。

二、compiler:编译

maven-compiler-plugin——编译,管 JDK 版本:

maven-compiler-plugin(编译插件):
  负责编译 Java 源码(javac)
  绑定到 compile 阶段(编译主代码)和 test-compile(编译测试代码)

核心配置——JDK 版本:
  ① source/target(老写法):
     source:源码用哪个 Java 版本语法
     target:编译成哪个版本的字节码
     <source>17</source> <target>17</target>
  ② release(新写法,JDK 9+,推荐):
     <release>17</release>
     → 一次指定源码和目标版本(更简洁、更准确)

为什么要配 JDK 版本:
  默认可能用旧版本(Java 5/8),导致新语法不能用
  → 配 release/source/target 指定用哪个 Java 版本编译
  → 用了新语法(如 var、record)必须配够高的版本

Spring Boot 里(父 POM 管理):
  <properties><java.version>17</java.version></properties>
  → Spring Boot 父 POM 会转成 compiler 的配置

所以 compiler 插件编译代码、配 JDK 版本(release/source/target)

maven-compiler-plugin 编译 Java 源码(javac),绑定 compile(主代码)和 test-compile(测试代码)阶段。核心配置——JDK 版本source/target(老写法,源码语法版本/目标字节码版本)、release(新写法 JDK 9+ 推荐,一次指定源码和目标版本)。为什么配:默认可能用旧版本、新语法不能用、配 release 指定用哪个 Java 版本编译。Spring Boot 用 <java.version> 转成 compiler 配置。理解「maven-compiler-plugin 编译源码(绑定 compile/test-compile);配 JDK 版本:source/target(老)或 release(新推荐,一次指定);为什么配:默认可能旧版本新语法不能用;Spring Boot 用 java.version」,就掌握了 compiler 插件。

三、surefire 与 failsafe:测试

maven-surefire-plugin(单元测试)和 maven-failsafe-plugin(集成测试)

maven-surefire-plugin(单元测试):
  运行单元测试,绑定到 test 阶段(mvn test)
  默认测试类命名:*Test、Test*、*Tests、*TestCase

  配置:
    skipTests:跳过测试(mvn install -DskipTests)
    includes/excludes:包含/排除哪些测试
    parallel:并行运行测试
    生成测试报告(target/surefire-reports)

maven-failsafe-plugin(集成测试):
  运行集成测试,绑定到 integration-test / verify 阶段
  默认测试类命名:*IT、IT*、*ITCase

  为什么和 surefire 分开:
    ① 集成测试慢(真连数据库、启动容器)→ 和单元测试分开跑
    ② 集成测试失败不该立即中断构建
       failsafe 的 goal:integration-test(跑)+ verify(检查结果)
       → 跑完集成测试,在 verify 阶段才报失败
       → 保证"先跑完、清理(如关容器)、再报失败"(不留垃圾)

surefire vs failsafe(区别):
  surefire:单元测试(test 阶段、*Test)、失败立即停
  failsafe:集成测试(integration-test/verify、*IT)、
    跑完+清理+verify 才报失败
  → 分开:单元测试快跑、集成测试单独管理

跳过测试:
  -DskipTests:编译测试但不跑
  -Dmaven.test.skip=true:连测试都不编译(更彻底)

所以 surefire 跑单元测试(test 阶段)、failsafe 跑集成测试(分开管理)

maven-surefire-plugin(单元测试) 绑定 test 阶段(mvn test,默认测试类 *Test),配置 skipTests/includes/parallelmaven-failsafe-plugin(集成测试) 绑定 integration-test/verify 阶段(默认 *IT)。为什么分开① 集成测试慢(真连数据库)和单元测试分开跑、② 集成测试失败不该立即中断构建(failsafe 的 integration-test 跑 + verify 检查结果、跑完清理再报失败、不留垃圾)。surefire vs failsafe:surefire 单元测试失败立即停、failsafe 集成测试跑完清理再报。跳过测试-DskipTests(编译不跑)/-Dmaven.test.skip=true(连编译都跳)。理解「surefire 单元测试(test 阶段/*Test/skipTests)、failsafe 集成测试(integration-test/verify/*IT);分开因:集成测试慢+失败不该立即中断(跑完清理再报);跳过 -DskipTests(编译不跑)/maven.test.skip(连编译跳)」,就掌握了 surefire 和 failsafe。

四、打包插件:jar/shade/assembly

打包插件——jar/shade/assembly/spring-boot:

maven-jar-plugin(普通 jar):
  打一个普通 jar(只含项目自己的类,不含依赖)
  → 运行要靠 classpath 提供依赖(不能直接 java -jar)

maven-shade-plugin(fat jar,可重定位):
  打一个"fat jar / uber jar"——项目 + 所有依赖打进一个 jar
  → 能 java -jar 直接运行(依赖都在里面)
  特色功能——重定位(relocation):
    把依赖的包名"改掉"(如 com.google → myapp.shaded.com.google)
    → 避免和别的库的同名类冲突(写库时常用,避免依赖冲突)
  还能合并资源(META-INF/services 等)

maven-assembly-plugin(各种分发包):
  按"装配描述文件"打各种格式的分发包
  预定义描述:jar-with-dependencies(含依赖的 jar)
  也能打 tar.gz、zip 等(含 jar + 配置 + 脚本的完整分发包)
  → 最灵活(自定义打什么、什么格式)

spring-boot-maven-plugin(Spring Boot 可执行 jar):
  打 Spring Boot 的可执行 fat jar
  特殊结构:嵌套 jar(依赖 jar 原样放在 BOOT-INF/lib,
    用特殊的 JarLauncher 加载,见 executable-jar 题)
  → Spring Boot 应用用它(java -jar 直接跑)

区别(都能打含依赖的 jar):
  shade:把依赖的类"平铺"进一个 jar,能重定位(避免冲突)
  assembly:灵活的分发包(jar-with-dependencies 或其他格式)
  spring-boot:Spring Boot 的嵌套 jar 结构

选择:
  Spring Boot 应用 → spring-boot-maven-plugin
  普通可执行 fat jar → shade(尤其要重定位避免冲突)
  自定义分发包(含配置/脚本)→ assembly

所以打包:jar(普通)/shade(fat jar 可重定位)/assembly(分发包)/spring-boot

打包插件maven-jar-plugin(普通 jar,只含项目类不含依赖、运行靠 classpath)、maven-shade-plugin(fat jar/uber jar,项目+所有依赖打进一个 jar 能 java -jar 直接运行,特色重定位——把依赖包名改掉避免同名类冲突,写库常用)、maven-assembly-plugin(按装配描述打各种格式分发包 jar-with-dependencies/tar.gz,最灵活)、spring-boot-maven-plugin(Spring Boot 可执行 jar,嵌套 jar 结构 BOOT-INF/lib)。区别:shade 平铺依赖类能重定位、assembly 灵活分发包、spring-boot 嵌套 jar。选择:Spring Boot 用 spring-boot-maven-plugin、普通 fat jar 用 shade(要重定位避免冲突)、自定义分发包用 assembly。理解「打包插件:jar(普通不含依赖)/shade(fat jar 可重定位避免同名类冲突)/assembly(灵活分发包 tar.gz)/spring-boot(嵌套 jar);选择 Spring Boot 用 spring-boot、fat jar 用 shade、分发包用 assembly」,就掌握了打包插件。

五、其他常用插件

补充其他常用插件:

其他常用插件:
  ① maven-resources-plugin:处理资源文件
     复制 src/main/resources 到 target,支持属性替换(@key@ 或 ${key})

  ② maven-source-plugin:打源码 jar(xxx-sources.jar)
     → 发布库时附带源码

  ③ maven-javadoc-plugin:生成 Javadoc、打 javadoc jar

  ④ maven-dependency-plugin:分析/复制依赖
     dependency:tree(依赖树)、dependency:analyze(分析未用/缺失的依赖)

  ⑤ maven-deploy-plugin / maven-install-plugin:
     deploy 到远程仓库、install 到本地仓库

  ⑥ jacoco-maven-plugin:测试覆盖率(生成覆盖率报告)

  ⑦ versions-maven-plugin:管理版本(批量更新依赖版本)

  ⑧ maven-enforcer-plugin:强制规则(如禁止某些依赖、统一版本)

  ⑨ flatten-maven-plugin:扁平化 POM(多模块发布)

常用的 goal(命令):
  mvn clean:清理 target(clean 生命周期)
  mvn compile/test/package/install/deploy
  mvn dependency:tree:看依赖树
  mvn help:effective-pom:看最终生效的 POM

所以还有 resources/source/javadoc/dependency/jacoco 等常用插件

其他常用插件:maven-resources-plugin(处理资源、属性替换)、maven-source-plugin(源码 jar)、maven-javadoc-plugin(Javadoc)、maven-dependency-plugin(依赖树 dependency:tree/分析 dependency:analyze)、maven-deploy/install-plugin(发布到远程/本地仓库)、jacoco-maven-plugin(测试覆盖率)、versions-maven-plugin(版本管理)、maven-enforcer-plugin(强制规则)。常用命令:mvn clean/compile/test/package/installmvn dependency:tree。理解「其他插件:resources(资源属性替换)/source(源码 jar)/javadoc/dependency(树/分析)/deploy-install(发布)/jacoco(覆盖率)/versions(版本)/enforcer(规则);命令 mvn clean/compile/test/package/dependency:tree」,就掌握了其他常用插件。

六、实践与总结

总结 Maven 插件的实践:

常用插件速查:
  编译(JDK 版本)→ maven-compiler-plugin(release/source/target)
  单元测试 → maven-surefire-plugin(test 阶段)
  集成测试 → maven-failsafe-plugin(integration-test/verify)
  打 fat jar → maven-shade-plugin(可重定位)
  打分发包 → maven-assembly-plugin
  Spring Boot jar → spring-boot-maven-plugin
  依赖分析 → maven-dependency-plugin(dependency:tree)
  测试覆盖率 → jacoco-maven-plugin

实践建议:
  ① 配 compiler 的 JDK 版本(release,用新语法必须配)
  ② 单元测试用 surefire、集成测试用 failsafe(分开)
  ③ Spring Boot 应用用 spring-boot-maven-plugin
  ④ 普通可执行 jar 用 shade、要避免依赖冲突用 shade 重定位
  ⑤ 用 dependency:tree 排查依赖冲突

理解 Maven 的关键:
  Maven 是插件框架
  生命周期阶段 + 插件 goal 绑定 = 实际构建工作
  → 遇到构建问题,先看"哪个插件的哪个 goal"

核心总结:
  Maven 是插件框架(阶段+插件 goal 绑定)
  compiler(编译/JDK 版本)/surefire(单元测试)/failsafe(集成测试)
  /shade(fat jar 可重定位)/assembly(分发包)/spring-boot(可执行 jar)
  理解 Maven=理解阶段+插件 goal 绑定

Maven 插件速查:编译用 compiler(JDK 版本)、单元测试用 surefire、集成测试用 failsafe、fat jar 用 shade(可重定位)、分发包用 assembly、Spring Boot jar 用 spring-boot、依赖分析用 dependency、覆盖率用 jacoco。实践:配 compiler JDK 版本、单元测试 surefire 集成测试 failsafe 分开、Spring Boot 用 spring-boot-maven-plugin、fat jar 用 shade、dependency:tree 排查冲突。理解 Maven 的关键:插件框架、生命周期阶段+插件 goal 绑定、遇构建问题先看哪个插件哪个 goal。理解「插件速查:编译 compiler/单元 surefire/集成 failsafe/fat jar shade/分发包 assembly/Spring Boot spring-boot/依赖 dependency/覆盖率 jacoco;实践配 JDK 版本+测试分开+Spring Boot 用专用插件;理解 Maven=阶段+插件 goal 绑定」,就掌握了实践与总结。

记忆钩子:「Maven 是插件执行框架(核心什么都不做、工作靠插件),生命周期阶段(validate→compile→test→package→install→deploy)+插件 goal 绑定=实际工作;常用插件:①maven-compiler-plugin(编译,配 JDK 版本 release/source/target)②maven-surefire-plugin(单元测试,test 阶段,*Test,skipTests)③maven-failsafe-plugin(集成测试,integration-test/verify,*IT,和 surefire 分开因集成测试慢+失败不该立即中断跑完清理再报)④maven-jar-plugin(普通 jar 不含依赖)⑤maven-shade-plugin(fat jar 含依赖可 java -jar,特色重定位改依赖包名避免同名类冲突)⑥maven-assembly-plugin(灵活分发包 jar-with-dependencies/tar.gz)⑦spring-boot-maven-plugin(Spring Boot 嵌套 jar);其他:dependency(树/分析冲突)/jacoco(覆盖率)/resources/source;理解 Maven=阶段+插件 goal 绑定」

七、常见误区与追问

  • 误区:Maven 自己会编译、测试、打包。 Maven 本身是插件框架、几乎什么都不做——所有实际工作都是插件干的:编译是 maven-compiler-plugin、测试是 maven-surefire-plugin、打包是 maven-jar-plugin/shade 等;这些插件的 goal 绑定到生命周期的各个阶段,mvn compile/test/package 触发的是绑定到这些阶段的插件 goal。
  • 误区:surefire 和 failsafe 都是跑测试、没区别。 surefire 跑单元测试(test 阶段、默认 *Test 命名、失败立即停);failsafe 跑集成测试(integration-test/verify 阶段、默认 *IT 命名);分开是因为集成测试慢(真连数据库、启动容器)、且集成测试失败不该立即中断构建——failsafe 让集成测试跑完、执行清理(如关容器),在 verify 阶段才报失败,不留垃圾。
  • 误区:shade、assembly、spring-boot-maven-plugin 打的 jar 一样。 都能打含依赖的 jar,但方式不同:shade 把依赖的类平铺进一个 jar、还能「重定位」(改依赖的包名,避免同名类冲突,写库常用);assembly 最灵活(按描述文件打各种格式,如 jar-with-dependencies、tar.gz 含配置和脚本的完整分发包);spring-boot-maven-plugin 用特殊的嵌套 jar 结构(依赖 jar 原样放在 BOOT-INF/lib、用 JarLauncher 加载),Spring Boot 应用专用。
  • 误区:配了 java.version 就够了,不用配 compiler-plugin。 Spring Boot 项目里 java.version 会被父 POM 转成 compiler-plugin 的配置(所以够用);但非 Spring Boot 项目,要直接配 maven-compiler-plugin 的 release(或 source/target)指定 JDK 版本;否则可能用默认的旧版本编译、新语法(var、record)不能用。
  • 追问:Maven 的编译、测试、打包分别是哪些插件干的? 编译:maven-compiler-plugin(compile goal 编译主代码、testCompile goal 编译测试代码,绑定 compile/test-compile 阶段,配 JDK 版本 release/source/target);单元测试:maven-surefire-plugin(test goal,绑定 test 阶段,默认跑 *Test 命名的测试类);集成测试:maven-failsafe-plugin(integration-test + verify goal,默认跑 *IT);打包:maven-jar-plugin(普通 jar)或 maven-shade-plugin/maven-assembly-plugin/spring-boot-maven-plugin(含依赖的 fat jar),绑定 package 阶段;Maven 是插件框架,这些插件的 goal 绑定到生命周期阶段完成实际工作。
  • 追问:maven-shade-plugin 的「重定位(relocation)」是干什么的? 把依赖的包名「改掉」(如把 com.google.guava 重命名为 myapp.shaded.com.google.guava,并同步修改引用)——目的是避免和别的库的同名类冲突:当你写一个库,它依赖某个版本的 guava,而使用你的库的项目可能依赖另一个版本的 guava,两个版本的同名类会冲突;用 shade 的重定位把你依赖的 guava 改名藏起来(shaded),就不会和使用者的 guava 冲突;这是写库/工具时避免依赖冲突的常用手段。
  • 追问:怎么理解 Maven 的生命周期和插件的关系? Maven 的构建生命周期(validate → compile → test → package → verify → install → deploy)是「阶段的骨架」,只是定义了顺序执行的步骤,本身不做具体工作;每个阶段执行什么,取决于「绑定到这个阶段的插件目标(goal)」——比如 compile 阶段绑定了 maven-compiler-plugin:compile、test 阶段绑定了 maven-surefire-plugin:test、package 阶段绑定了打包插件的 goal;执行 mvn package 会依次执行 package 及之前所有阶段绑定的插件 goal;所以理解 Maven = 理解「生命周期阶段 + 插件 goal 绑定」,遇到构建问题先看是「哪个阶段的哪个插件的哪个 goal」。

八、加强记忆

Maven 本身是「插件执行框架」——核心几乎什么都不做,所有实际工作(编译、测试、打包)都由「插件(plugin)」完成,插件的「目标(goal)」绑定到构建生命周期的各个阶段validate → compile → test → package → verify → install → deploy)。常用插件maven-compiler-plugin(编译,配 JDK 版本 release/source/target);maven-surefire-plugin单元测试,绑定 test 阶段,默认 *TestskipTests 跳过);maven-failsafe-plugin集成测试,绑定 integration-test/verify,默认 *IT,和 surefire 分开因集成测试慢 + 失败不该立即中断,跑完清理再报失败);maven-jar-plugin(普通 jar,不含依赖);maven-shade-pluginfat jar/uber jar,项目+所有依赖打进一个 jar 能 java -jar,特色重定位——改依赖包名避免同名类冲突,写库常用);maven-assembly-plugin(按装配描述打各种分发包,最灵活);spring-boot-maven-plugin(Spring Boot 可执行 jar,嵌套 jar 结构);还有 dependencydependency:tree 排查冲突)、jacoco(覆盖率)等。理解 Maven 的关键 = 理解「生命周期阶段 + 插件 goal 绑定」mvn compile/test/package 触发绑定到这些阶段的插件 goal),遇到构建问题先看「哪个插件的哪个 goal」。一句话「**Maven 是插件框架(工作靠插件 goal 绑定生命周期);compiler 编译(JDK 版本)/surefire 单元测试(test/Test)/failsafe 集成测试(integration-test/IT,和 surefire 分开)/shade 打 fat jar(可重定位避免同名类冲突)/assembly 分发包/spring-boot 可执行 jar;理解 Maven=阶段+插件 goal 绑定」。