乐途乐途
主页
  • 计算机基础

    • TCP/IP协议
    • Linux命令
    • HTTP协议
  • 数据库

    • SQL
    • MySQL 5.7
  • 编程语言

    • C语言
    • Python2
    • Python3
  • 数据格式

    • JSON
    • XML
  • 认证与安全

    • JWT
  • 工具

    • Markdown
  • Git

    • GitFlow
  • Quartz

    • Quartz
  • Java

    • MyBatis
    • Spring
    • Spring MVC
    • Maven 入门
    • Maven 进阶
    • Java 设计模式
  • 缓存

    • Redis
联系
阿里云
主页
  • 计算机基础

    • TCP/IP协议
    • Linux命令
    • HTTP协议
  • 数据库

    • SQL
    • MySQL 5.7
  • 编程语言

    • C语言
    • Python2
    • Python3
  • 数据格式

    • JSON
    • XML
  • 认证与安全

    • JWT
  • 工具

    • Markdown
  • Git

    • GitFlow
  • Quartz

    • Quartz
  • Java

    • MyBatis
    • Spring
    • Spring MVC
    • Maven 入门
    • Maven 进阶
    • Java 设计模式
  • 缓存

    • Redis
联系
阿里云
  • 学习路径
  • 第1章 介绍与核心概念

    • Maven是什么
    • 约定优于配置
  • 第2章 安装与配置

    • 安装与验证
    • settings.xml
    • 本地仓库与镜像
  • 第3章 POM与项目坐标

    • POM
    • GAV坐标
    • packaging
  • 第4章 标准目录布局

    • 标准目录布局
  • 第5章 依赖机制

    • dependencies
    • scope
    • 依赖传递
    • 依赖冲突与调解
    • exclusions
    • optional
    • dependencyManagement
  • 第6章 仓库

    • 仓库体系
    • 本地仓库
    • 远程仓库与镜像
    • 私服
  • 第7章 构建生命周期

    • 生命周期概述
    • clean 生命周期
    • default 生命周期
    • site 生命周期
    • 生命周期与插件绑定
  • 第8章 插件

    • 插件概述
    • maven-compiler-plugin
    • maven-surefire-plugin
    • maven-war-plugin
  • 第9章 继承与聚合

    • parent继承
    • 聚合
    • BOM
    • properties
  • 第10章 属性与资源过滤

    • 资源过滤
    • Profile
  • 第11章 常用命令

    • mvn compile
    • mvn test
    • mvn package
    • mvn clean
    • mvn install
    • mvn dependency:tree
  • 第12章 常见问题与最佳实践

    • 依赖冲突排查
    • 最佳实践

插件概述

本章是"插件"章节的总纲。理解插件在 Maven 中的核心地位,是后续学习具体插件(如 compiler、surefire、war)的前提。如果说生命周期是"剧本",插件就是"演员"——剧本规定了场次,演员负责登台表演。


核心机制

这句话的潜台词是:Maven 本身几乎什么都不做,所有实际工作都由插件完成。Maven 引擎只负责三件事:

  1. 解析 pom.xml
  2. 计算生命周期阶段
  3. 在正确的阶段调用正确的插件

编译代码?maven-compiler-plugin 干的。运行测试?maven-surefire-plugin 干的。打包 WAR?maven-war-plugin 干的。Maven 只是那个拿着喇叭喊"各部门准备——Action!"的导演。

"Maven 本身不干活,插件干活"

这是理解 Maven 插件体系的第一性原理。让我们拆解一次 mvn compile 的真实执行过程:

步骤Maven 引擎做什么插件做什么
1读取 pom.xml,确认当前阶段是 compile—
2查找 compile 阶段绑定的默认插件maven-compiler-plugin 准备就绪
3解析插件坐标,从本地/远程仓库下载插件插件 JAR 被加载到内存
4调用插件的 compile 目标(goal)调用 JDK 的 javac 编译源代码
5收集编译结果,准备进入下一阶段生成 .class 文件到 target/classes

可以看到,Maven 引擎是"调度中心",插件是"施工队"。没有插件,Maven 就是一个空壳。

插件坐标:GAV 的另一种形式

插件本身也是 Maven 构件,因此也有坐标。插件坐标的格式与普通依赖完全一致:

groupId:artifactId:version

例如 maven-compiler-plugin 的坐标是:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>3.11.0</version>
</plugin>

Maven boot-maven-plugin`)。

插件目标(Goal)

一个插件可以包含多个目标(Goal),每个目标对应一个具体任务。例如 maven-compiler-plugin 有两个核心目标:

目标作用
compiler:compile编译主源代码(src/main/java)
compiler:testCompile编译测试代码(src/test/java)

生命周期阶段与插件目标的绑定是 Maven 自动运转的关键。compile 阶段默认绑定 compiler:compile,test-compile 阶段默认绑定 compiler:testCompile。

生活类比:剧组的导演与演员

想象 Maven 是一个电影剧组:

  • Maven 引擎 = 导演。导演不亲自化妆、不亲自打光、不亲自表演。导演的工作是:看剧本(pom.xml)、排场次(生命周期)、喊"Action"(调用插件)。
  • 插件 = 各部门工作人员。摄影组(compiler-plugin)负责拍摄,灯光组(surefire-plugin)负责照亮测试场景,后期组(jar-plugin)负责剪辑成片。
  • 目标(Goal) = 每个部门的具体任务。摄影组今天拍外景(compile),明天拍绿幕(testCompile)。

没有导演,剧组一盘散沙;没有演员和工作人员,导演只能对着空场地发呆。Maven 和插件的关系,就是导演与剧组的关系。


图示

上图展示了 Maven 的核心架构:引擎负责调度,插件负责执行,最终产生构建产物。开发者通过 pom.xml 声明"需要什么插件、用什么版本、配什么参数",Maven 引擎在生命周期阶段触发插件执行。


完整示例

场景

飞翔科技的 employee-system 项目需要支持 Java 17,并且要在打包时排除某些配置文件。CTO 大翔让架构师白歌调研:这些工作到底是 Maven 做的,还是插件做的?

操作前:项目状态

当前 pom.xml 没有显式声明任何插件,完全依赖 Maven 的默认绑定:

<?xml version="1.0" encoding="UTF-8"?>
<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
                             http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.feixiang</groupId>
    <artifactId>employee-system</artifactId>
    <version>1.0.0</version>
    <packaging>jar</packaging>

    <dependencies>
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter</artifactId>
            <version>5.9.2</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
</project>

操作步骤:显式声明插件

白歌决定显式声明编译插件和打包插件,以精确控制构建行为:

<build>
    <plugins>
        <!-- 编译插件:控制 Java 版本 -->
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.11.0</version>
            <configuration>
                <source>17</source>
                <target>17</target>
                <encoding>UTF-8</encoding>
            </configuration>
        </plugin>

        <!-- JAR 打包插件:排除配置文件 -->
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-jar-plugin</artifactId>
            <version>3.3.0</version>
            <configuration>
                <excludes>
                    <exclude>**/application-dev.yml</exclude>
                </excludes>
            </configuration>
        </plugin>
    </plugins>
</build>

操作结果及分析

执行 mvn clean compile:

$ mvn clean compile
[INFO] --- maven-clean-plugin:3.2.0:clean (default-clean) @ employee-system ---
[INFO] Deleting C:\workspace\employee-system\target
[INFO] --- maven-resources-plugin:3.3.1:resources (default-resources) @ employee-system ---
[INFO] Copying 1 resource
[INFO] --- maven-compiler-plugin:3.11.0:compile (default-compile) @ employee-system ---
[INFO] Compiling 5 source files to C:\workspace\employee-system\target\classes
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS

变化分析:

  • 小崔注意到:即使没有在 pom.xml 里写 maven-clean-plugin 和 maven-resources-plugin,它们依然被执行了——这是 Maven 的隐式绑定
  • 白歌确认:maven-compiler-plugin:3.11.0 被显式调用,而不是默认的 3.1.0 版本
  • 李眉发现:最终 JAR 包里确实没有 application-dev.yml,因为 maven-jar-plugin 按配置排除了它

关键结论:所有实际工作都是插件完成的。Maven 引擎只是按生命周期顺序,依次触发 clean-plugin → resources-plugin → compiler-plugin。


易错点与常见问题

误区一:"Maven 帮我编译了代码"

错误认知:"我运行 mvn compile,Maven 把代码编译成了 .class 文件。"

纠正:编译代码的是 maven-compiler-plugin,不是 Maven 本身。Maven 只是找到了 compile 阶段绑定的插件,并调用了它的 compile 目标。如果你把 maven-compiler-plugin 从项目中彻底移除(虽然很难做到,因为默认绑定存在),mvn compile 将无事可做。

误区二:插件版本无所谓,Maven 会自动选最新版

错误认知:"插件版本我不写,Maven 肯定给我用最新的,越新越好。"

纠正:Maven 不会自动选择插件的最新版本。如果不显式声明版本,Maven 会使用**超级 POM(Super POM)**中定义的默认版本。这些默认版本通常比较保守(例如 maven-compiler-plugin 默认可能是 3.1.0),可能不支持 Java 17 等新特性。显式声明插件版本是生产环境的最佳实践,它确保所有团队成员和 CI/CD 环境使用完全一致的插件行为。

误区三:插件和依赖是一回事

错误认知:"我在 <dependencies> 里写 maven-compiler-plugin,和在 <plugins> 里写,效果一样吧?"

纠正:完全不一样。<dependencies> 声明的是项目运行时需要的外部库(如 Spring、MySQL 驱动),它们会被打包进最终产物或用于编译期 classpath。<plugins> 声明的是构建工具本身,只在构建阶段使用,不会被打包进最终产物。把插件写到 <dependencies> 里,不仅无法让 Maven 在构建时调用它,还会把构建工具污染到项目的运行时依赖中。


小结

插件是 Maven 的"执行层",Maven 引擎是"调度层"。Maven 本身不干活,插件干活——这是理解 Maven 架构的第一性原理。每个插件通过坐标(GAV)唯一标识,通过目标(Goal)完成具体任务。生命周期阶段与插件目标的绑定,构成了 Maven"声明式构建"的自动运转机制。

本章与全局的关系:本章回答了"插件是什么、为什么重要"。接下来四节将分别深入讲解 maven-compiler-plugin、maven-surefire-plugin、maven-war-plugin 等核心插件的具体配置和使用场景。

下一页
maven-compiler-plugin