Maven 常用的插件有哪些?compiler、surefire、shade、assembly 各是干什么的?
简化版
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 | 打普通 jar | package |
| maven-shade-plugin | 打 fat jar(含依赖,可重定位) | package |
| maven-assembly-plugin | 打各种分发包 | package |
| spring-boot-maven-plugin | 打 Spring Boot 可执行 jar | package |
| 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 compile、mvn test、mvn package触发的是绑定到这些阶段的插件的 goal。Maven 的构建生命周期(validate → compile → test → package → verify → install → deploy)只是「阶段的骨架」,每个阶段执行什么,取决于「绑定到这个阶段的插件目标(goal)」——mvn compile执行maven-compiler-plugin的compilegoal、mvn test执行maven-surefire-plugin的testgoal、mvn package执行打包插件的 goal。所以理解 Maven = 理解「生命周期阶段 + 插件 goal 绑定」。几个高频区分:surefire(单元测试)vsfailsafe(集成测试)——分开是因为集成测试慢、可能失败但不该中断构建(failsafe 的 goal 让集成测试失败不立即停);shadevsassemblyvsspring-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/parallel。maven-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/install、mvn 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 阶段,默认 *Test,skipTests 跳过);③ maven-failsafe-plugin(集成测试,绑定 integration-test/verify,默认 *IT,和 surefire 分开因集成测试慢 + 失败不该立即中断,跑完清理再报失败);④ maven-jar-plugin(普通 jar,不含依赖);⑤ maven-shade-plugin(fat jar/uber jar,项目+所有依赖打进一个 jar 能 java -jar,特色重定位——改依赖包名避免同名类冲突,写库常用);⑥ maven-assembly-plugin(按装配描述打各种分发包,最灵活);⑦ spring-boot-maven-plugin(Spring Boot 可执行 jar,嵌套 jar 结构);还有 dependency(dependency: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 绑定」。