Maven 插件详解
官方原文:
"Maven is - at its heart - a plugin execution framework; all work is done by plugins. Looking for a specific goal to execute? This page lists the core plugins and others. There are the build and the reporting plugins:
Build plugins will be executed during the build and they should be configured in the
<build/>element from the POM.Reporting plugins will be executed during the site generation and they should be configured in the
<reporting/>element from the POM. Because the result of a Reporting plugin is part of the generated site, Reporting plugins should be both internationalized and localized."—— Maven 官方文档
一、核心理解:Maven 的本质
Maven 本质上是一个插件执行框架;所有的工作都由插件完成。
这句话揭示了 Maven 的设计哲学:
| 说法 | 含义 |
|---|---|
| "Maven 是插件执行框架" | Maven 本身不实现任何构建功能,它只负责调度和编排 |
| "所有工作都由插件完成" | 你做的所有操作——编译、测试、打包、部署——背后都是某个插件在执行 |
| "寻找特定 Goal?" | 如果你想知道某个任务怎么做,本质上是在找哪个插件的哪个 Goal |
Maven 架构示意
┌──────────────────────────────────────────────────────────────┐
│ Maven │
│ (插件执行框架) │
│ │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ 生命周期 │ │
│ │ clean → compile → test → package → deploy │ │
│ └──────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ 插件执行器 │ │
│ │ │ │ │ │ │ │
│ │ ▼ ▼ ▼ ▼ │ │
│ │ 编译插件 测试插件 打包插件 部署插件 │ │
│ └──────────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────┘
二、插件的定义
2.1 通俗理解
Maven 本身只是一个骨架,它定义了生命周期(Lifecycle)——即构建项目要经历哪些阶段(编译、测试、打包、部署等),但它不干活,真正干活的是插件。
可以把 Maven 比作一个流水线平台,插件就是工位上的工人:
| Maven | 插件 |
|---|---|
| 定义构建流程(生命周期) | 执行具体的构建任务 |
| 告诉你在哪个阶段做什么 | 负责实际把事情做出来 |
比如:package 阶段要打包 | maven-jar-plugin 负责打出 JAR 包 |
2.2 官方定义
Maven 插件是一个或多个 Goal(目标) 的集合,每个 Goal 负责执行一个具体的构建任务。插件通过 Goal 绑定到生命周期的某个 Phase(阶段) 上执行。
- Plugin(插件):一组功能的集合,提供多个 Goal
- Goal(目标):插件中一个具体、可执行的原子操作
三、插件的两种类型
根据官方定义,Maven 插件分为两大类:
| 构建插件(Build Plugins) | 报告插件(Reporting Plugins) | |
|---|---|---|
| 执行时机 | 构建生命周期中(compile、test、package 等阶段) | 生成站点文档时(mvn site) |
| 配置位置 | <build><plugins> | <reporting> |
| 产出 | 构建产物(JAR、WAR、Docker 镜像等) | 项目报告、文档(HTML 页面) |
| 本地化要求 | 不需要 | 需要(面向用户阅读的报告) |
| 示例 | maven-compiler-plugin、docker-maven-plugin | maven-javadoc-plugin、maven-surefire-report-plugin |
3.1 构建插件(Build Plugins)
官方定义:"Build plugins will be executed during the build and they should be configured in the <build/> element from the POM."
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.11.0</version>
<configuration>
<source>17</source>
<target>17</target>
</configuration>
</plugin>
<plugin>
<groupId>io.fabric8</groupId>
<artifactId>docker-maven-plugin</artifactId>
<version>0.43.4</version>
<configuration>
<images>
<image>
<name>myapp:${project.version}</name>
<build>
<contextDir>${project.basedir}</contextDir>
</build>
</image>
</images>
</configuration>
</plugin>
</plugins>
</build>
3.2 报告插件(Reporting Plugins)
官方定义:"Reporting plugins will be executed during the site generation and they should be configured in the <reporting/> element from the POM. Because the result of a Reporting plugin is part of the generated site, Reporting plugins should be both internationalized and localized."
<reporting>
<plugins>
<!-- JavaDoc 报告(支持多语言) -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>3.5.0</version>
<configuration>
<aggregate>true</aggregate>
<locale>zh_CN</locale> <!-- 本地化:中文 -->
</configuration>
</plugin>
<!-- 单元测试报告 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-report-plugin</artifactId>
<version>3.0.0-M9</version>
<configuration>
<locale>zh_CN</locale>
</configuration>
</plugin>
</plugins>
</reporting>
3.3 两种插件的对比图解
Maven 构建生命周期 Maven Site 生命周期
───────────────────── ────────────────────
compile ──▶ maven-compiler-plugin pre-site
│ │
test ──▶ maven-surefire-plugin site ──▶ 报告插件生成报告
│ │
package ──▶ maven-jar-plugin post-site
│ │
deploy ──▶ maven-deploy-plugin site-deploy
▲ ▲
│ │
构建插件(Build Plugins) 报告插件(Reporting Plugins)
产出:JAR/WAR/Docker 镜像 产出:HTML 文档/报告
四、插件的组成结构
每个插件由三部分组成:
<plugin>
<groupId>io.fabric8</groupId> <!-- 组织ID -->
<artifactId>docker-maven-plugin</artifactId> <!-- 插件ID -->
<version>0.43.4</version> <!-- 版本 -->
<configuration>...</configuration> <!-- 配置 -->
<executions>...</executions> <!-- 执行绑定 -->
</plugin>
- 坐标(GAV):Maven 用来下载和识别插件的唯一标识
- Goal:插件提供的具体功能,如
docker:build、docker:push - 配置:定制插件的行为
- 执行绑定:将特定 Goal 绑定到生命周期的某个阶段
五、执行插件的方式
方式一:通过命令行直接调用
# 格式:mvn 插件前缀:目标
mvn docker:build # 构建镜像
mvn docker:push # 推送镜像
mvn spring-boot:run # 运行 Spring Boot 应用
mvn clean:clean # 清理
方式二:绑定到生命周期自动执行
<plugin>
<executions>
<execution>
<phase>install</phase> <!-- 在 install 阶段执行 -->
<goals>
<goal>build</goal> <!-- 执行 build 目标 -->
</goals>
</execution>
</executions>
</plugin>
这样当运行
mvn install时,docker:build会被自动执行。
方式三:使用完整坐标调用
# 格式:mvn groupId:artifactId:version:goal
mvn io.fabric8:docker-maven-plugin:0.43.4:build
六、插件前缀与完整坐标
Maven 通过插件前缀简化命令,前缀映射在插件的 META-INF/maven/plugin.xml 中定义:
| 简写命令 | 实际执行的完整坐标 | 说明 |
|---|---|---|
mvn docker:build | mvn io.fabric8:docker-maven-plugin:0.43.4:build | 使用前缀 docker |
mvn spring-boot:run | mvn org.springframework.boot:spring-boot-maven-plugin:run | 使用前缀 spring-boot |
mvn compiler:compile | mvn org.apache.maven.plugins:maven-compiler-plugin:compile | 核心插件前缀 |
settings.xml 中的 <pluginGroups> 可以自定义前缀:
<settings>
<pluginGroups>
<pluginGroup>io.fabric8</pluginGroup>
<pluginGroup>org.springframework.boot</pluginGroup>
</pluginGroups>
</settings>
七、插件与依赖的区别
| 插件 (Plugin) | 依赖 (Dependency) | |
|---|---|---|
| 作用时机 | 构建时执行 | 编译/运行时使用 |
| 用途 | 执行构建任务(编译、打包、测试等) | 提供代码所需的功能库 |
| 产物 | 不进入最终应用包 | 被打入最终应用包 |
| 位置 | <build><plugins> 或 <reporting> | <dependencies> |
简单说:依赖是给代码用的,插件是给构建过程用的。
八、常见插件分类
| 分类 | 插件示例 | 用途 | 类型 |
|---|---|---|---|
| 编译构建 | maven-compiler-plugin | 编译 Java 代码 | Build |
| 打包 | maven-jar-plugin、maven-war-plugin | 打包 JAR/WAR | Build |
| 测试 | maven-surefire-plugin | 运行单元测试 | Build |
| 容器化 | docker-maven-plugin | 构建 Docker 镜像 | Build |
| 文档 | maven-javadoc-plugin | 生成 JavaDoc | Reporting |
| 测试报告 | maven-surefire-report-plugin | 生成测试报告 | Reporting |
| 代码质量 | maven-pmd-plugin、spotbugs-maven-plugin | 静态代码检查 | Reporting/Build |
| 发布部署 | maven-deploy-plugin | 部署到仓库 | Build |
九、为什么"所有工作都由插件完成"
这个设计哲学解释了三个关键现象:
- 为什么 Maven 不需要安装"功能模块"?
- 插件是按需下载的,用的时候才从 Maven 仓库拉取
- 为什么 Maven 可以无限扩展?
- 任何人都可以编写 Maven 插件,没有功能边界
- 为什么 Maven 说"不够用就自己写插件"?
- 因为这就是它的核心设计模式
十、总结
| 关键点 | 说明 |
|---|---|
| Maven 的本质 | 插件执行框架,自身不干活 |
| 构建插件 | 配置在 <build>,在构建生命周期中执行,产出代码产物 |
| 报告插件 | 配置在 <reporting>,在站点生成时执行,产出文档报告 |
| Goal | 插件中最小的执行单元,如 docker:build |
| 执行方式 | 命令行直接调用 / 绑定生命周期 / 完整坐标调用 |
| 与依赖的区别 | 插件给构建用,依赖给代码用 |
一句话总结:Maven 只是一个"导演"(插件执行框架),自己不干活,所有"演员"(插件)完成具体工作;构建插件在编译打包时出场(产出代码产物),报告插件在生成文档时出场(产出项目报告)。
参考链接:
- Maven 官方插件列表
- Maven 插件开发指南