Maven
Maven By Example
archetype:generate
1mvn archetype:generate \
2 -DgroupId=org.sonatype.mavenbook.ch03 \
3 -DartifactId=simple \
4 -DarchetypeGroupId=org.apache.maven.archetypes \
5 -DarchetypeArtifactId=maven-archetype-quickstart \
6 -DinteractiveMode=false这个命令是 maven-archetype-plugin 插件的 generate 目标。它的核心功能是:根据一个原型(Archetype)来生成一个新项目的骨架
插件前缀解析 (Plugin Prefix Resolution)
为什么 maven-archetype-plugin 可以直接简写为 archetype 使用?
这个规则是 Maven 内部机制和插件命名规范共同作用的结果,具体规定在以下两个地方:
- Maven 的核心内置配置 (Built-in Configuration):规定了“去哪里找”
- 插件本身的元数据 (Plugin Metadata):规定了“我叫什么”
当你执行一个命令,比如 mvn archetype:generate 时,Maven 并不知道 archetype 是什么。它会执行一个叫做“前缀解析”的查找过程,来把这个简短的前缀(prefix)映射到一个完整的插件坐标org.apache.maven.plugins:maven-archetype-plugin (groupId:artifactId)。
遵循以下规则:
- 查找默认的插件组 (Default Plugin Groups)
Maven 的核心配置中,预先定义了一个默认的插件组列表 (pluginGroups)。其中最重要的、硬编码在程序里的就是:org.apache.maven.plugins - 若插件元数据文件定义了
<goalPrefix>如果插件的元数据文件(通常是META-INF/maven/plugin.xml)中定义了<goalPrefix>,Maven 会直接使用这个前缀来匹配插件。例如:
1<project>
2 ...
3 <build>
4 ...
5 <plugins>
6 ...
7 <plugin>
8 <artifactId>maven-plugin-plugin</artifactId>
9 <version>3.15.1</version>
10 <configuration>
11 ...
12 <goalPrefix>somePrefix</goalPrefix>
13 </configuration>
14 </plugin>
15 </plugins>
16 </build>
17</project>上述配置将允许用户通过前缀 somePrefix 来引用你的插件,如下例所示:
1mvn somePrefix:goal- 根据命名规范进行匹配
当 Maven 拿到一个前缀(比如 archetype)时,它会尝试在这个默认的插件组 (
org.apache.maven.plugins) 中寻找一个符合命名规范的 artifactId。匹配的模式主要有两种:maven-${prefix}-plugin(官方插件最常用的模式)${prefix}-maven-plugin同样的道理也适用于其他官方插件:mvn compiler:compile -> compiler被解析为maven-compiler-pluginmvn surefire:test -> surefire被解析为maven-surefire-plugin
在哪里可以自定义插件组(Plugin Groups)?
可以在 settings.xml 文件中扩展插件组列表 (pluginGroups),添加 <pluginGroups> 标签,把常用的第三方插件的 groupId 加进去。
例如: 如果你经常使用 Spring Boot 的插件,它的 groupId 是 org.springframework.boot。你可以这样配置:
1<settings>
2 ...
3 <pluginGroups>
4 <pluginGroup>org.springframework.boot</pluginGroup>
5 </pluginGroups>
6 ...
7</settings>配置好之后,原本需要输入完整命令:
1mvn org.springframework.boot:spring-boot-maven-plugin:run现在就可以简写为:
1mvn spring-boot:runMaven 会在默认的 org.apache.maven.plugins 中查找失败后,继续在你配置的 org.springframework.boot 组中查找,并成功匹配到 spring-boot-maven-plugin
我们来解析一下这些 -D 参数:
- -DgroupId, -DartifactId, -Dversion: 这三个定义了你的新项目的坐标。
- -DarchetypeGroupId, -DarchetypeArtifactId, -DarchetypeVersion: 这三个定义了你使用的原型的坐标。generate 命令需要明确知道你想用哪个模板来创建项目。
- -DinteractiveMode=false: 这个参数告诉 Maven 关闭交互模式,直接使用命令行提供的参数创建项目
事实上这里体现了约定优于配置(Convention over Configuration)原则。我们只是传入了 groupId 和 artifactId 这两个项目信息,Maven 就能根据这些信息和预定义的原型模板来生成一个完整的项目结构。
Maven 插件架构
Maven 核心本身非常小,它只包含了解析命令、管理 pom.xml 和下载插件等最基础的功能。所有具体的工作(如编译、打包)都委托给插件完成,并且这些插件只在需要时才会被下载。这种插件化架构将“做什么”(Maven 核心的生命周期)和“怎么做”(插件的具体实现)彻底解耦,带来了轻量、标准、灵活、可重用和易于维护的巨大优势。
一个Maven插件(Maven plugin)是一组或多个目标(goals)的集合。目标(goals)是一个具体任务,可以作为独立目标执行,也可以与其他目标一起作为更大构建的一部分执行。目标(goals)通过配置属性配置,这些属性可用于定制行为。例如,Compiler 插件的编译目标定义了一组配置参数,这些参数允许您指定目标 JDK 版本或是否使用编译器优化。
Maven 生命周期
Maven 的 构建生命周期 (Build Lifecycle) 是一个项目构建过程的有序步骤序列。
这个序列中的每一步都称为一个阶段 (Phase)。最常用的生命周期是默认生命周期 (Default Lifecycle),它从验证项目开始,到部署项目结束。
阶段本身只是一个“标记”,它本身不做任何事。真正的工作是由绑定(或附加)到这些阶段上的插件目标 (Plugin Goals) 完成的。
当 Maven 按顺序执行生命周期时,它会触发每个阶段上绑定的所有插件目标。从生命周期的起点开始,按顺序执行直到你指定的阶段为止。一个阶段可以绑定零个或多个目标。

生命周期阶段的定义是故意设计得比较模糊的,其具体含义取决于项目的类型。
例子:package 阶段对于一个普通 Java 项目(打包方式为 jar),意味着“创建一个 JAR 文件”,因此会绑定 jar:jar 这个目标。但对于一个 Web 项目(打包方式为 war),同一个 package 階段则可能意味着“创建一个 WAR 文件”。
Maven 的生命周期是 Maven 的核心定义的吗?
是的,绝对是。
Maven 的生命周期(Lifecycle)及其包含的阶段(Phase)的定义、顺序和骨架,是 Maven 框架最核心、最基础的组成部分。可以这样理解:
生命周期和阶段 (Lifecycle & Phase):是 Maven 定义的一套标准化的流程和步骤(比如先编译、再测试、后打包)。这个“流程图”是内置在 Maven 核心中的,它规定了“做什么”以及“按什么顺序做”。 插件 (Plugin):是具体“干活的人”。它们负责执行每个步骤的实际工作。 所以,Maven 核心提供了不变的、标准化的构建流程框架,而插件则提供了可变的、可配置的具体实现。这种分离正是 Maven 强大和灵活的关键。
完整的生命周期是什么?
A. default 生命周期(最重要的构建生命周期)
validate: 验证项目是否正确以及所有必需的信息是否可用。initialize: 初始化构建状态,例如设置属性。generate-sources: 生成任何需要包含在编译过程中的源代码。process-sources: 处理源代码,例如过滤值。generate-resources: 生成需要打包到项目中的资源文件。process-resources: 将资源文件复制并处理到目标目录,准备打包。compile: 编译项目的源代码。process-classes: 对编译生成的文件进行后处理,例如字节码增强。generate-test-sources: 生成测试用的源代码。process-test-sources: 处理测试源代码。generate-test-resources: 生成测试用的资源文件。process-test-resources: 将测试资源文件复制并处理到测试目标目录。test-compile: 编译测试源代码。process-test-classes: 对测试编译生成的文件进行后处理。test: 使用合适的单元测试框架(如 JUnit)运行测试。prepare-package: 在打包前进行准备工作。package: 将编译后的代码打包成可分发的格式,如 JAR、WAR 等。pre-integration-test: 在集成测试前进行准备。integration-test: 运行集成测试。post-integration-test: 在集成测试后进行清理。verify: 运行检查以验证包是否有效并符合质量标准。install: 将包安装到本地仓库,供本地其他项目依赖。deploy: 将最终的包复制到远程仓库,与其他开发者或项目共享。
B. clean 生命周期
用于清理上一次构建生成的文件。
主要阶段:
pre-clean: 在实际清理前执行一些操作。clean: 移除上一次构建生成的所有文件(通常是target目录)。post-clean: 在实际清理后执行一些操作。
C. site 生命周期
用于生成和部署项目站点(项目文档、报告等)。
主要阶段:
pre-site: 在生成站点文档前执行一些操作。site: 生成项目的站点文档。post-site: 在生成站点文档后执行一些操作,例如进行打包。site-deploy: 将生成的站点文档部署到指定的服务器。
一个插件如何绑定到生命周期中?
方式一:默认绑定 (由打包方式 <packaging> 决定)
这是 Maven “约定大于配置”理念的体现。Maven 会根据你在 pom.xml 中设置的打包方式(<packaging>,如 jar, war, pom),为核心的生命周期阶段绑定一套默认的插件目标。
- 如果你的
pom.xml中有<packaging>jar</packaging>(或者不写,因为jar是默认值)。 - Maven 会自动将
maven-compiler-plugin的compile目标绑定到compile阶段,将maven-surefire-plugin的test目标绑定到test阶段,将maven-jar-plugin的jar目标绑定到package阶段。 - 你完全不需要任何配置,执行
mvn package时,编译、测试、打包工作就会自动进行。
参考:Built-in Lifecycle Bindings
方式二:插件的“默认阶段绑定” (Default Phase Binding)
有些为特定目的而设计的插件(比如代码生成、资源处理),其作者已经预见到了它最常见的用例。因此,在插件本身的元数据中,开发者已经定义了它的默认绑定阶段。
例如,Modello 插件默认将其目标 modello:java 绑定到 generate-sources 阶段,我们只需要在 pom.xml 中添加如下配置:
1 <plugin>
2 <groupId>org.codehaus.modello</groupId>
3 <artifactId>modello-maven-plugin</artifactId>
4 <version>1.8.1</version>
5 <executions>
6 <execution>
7 <configuration>
8 <models>
9 <model>src/main/mdo/maven.mdo</model>
10 </models>
11 <version>4.0.0</version>
12 </configuration>
13 <goals>
14 <goal>java</goal>
15 </goals>
16 </execution>
17 </executions>
18 </plugin>您可能想知道为什么要使用 <executions> 元素。这样您就可以在需要时使用不同的配置多次运行同一个目标。还可以给单独的执行赋予一个 ID,这样在继承或应用配置文件时,就可以控制目标配置是被合并还是被转化为额外的执行。
方式三:手动绑定 (Manual Binding)
如果你需要更细粒度的控制,或者想要在特定阶段执行某个插件的目标,你可以手动绑定插件目标到生命周期阶段。
例如,假设有一个目标 display:time,它能在命令行中回声显示当前时间,你希望它在 process-test-resources 阶段运行,以显示测试何时开始。可以这样配置
1 <plugin>
2 <groupId>com.mycompany.example</groupId>
3 <artifactId>display-maven-plugin</artifactId>
4 <version>1.0</version>
5 <executions>
6 <execution>
7 <phase>process-test-resources</phase>
8 <goals>
9 <goal>time</goal>
10 </goals>
11 </execution>
12 </executions>
13 </plugin>Maven 命令格式
Maven 的命令格式通常是 mvn [phase] [plugin-prefix:goal] ,主要分为两大类:
-
执行生命周期阶段 (Lifecycle Phase)
- 命令格式:
mvn [phase] - 例子:
mvn compile,mvn package,mvn install - 目的: 对一个已经存在的项目,按照预定义的标准流程进行构建、测试、打包和安装。
- 工作方式: 当你执行一个
phase时,Maven 会按顺序执行该生命周期中从开始到指定阶段的所有步骤。例如,mvn install会依次执行validate,compile,test,package,install等一系列阶段。这些阶段的核心是处理你项目的源代码和资源。
- 命令格式:
-
直接执行插件目标 (Direct Plugin Goal)
- 命令格式:
mvn [plugin-prefix]:[goal] - 例子:
mvn archetype:generate,mvn clean:clean,mvn dependency:tree - 目的: 执行一个独立的、特定的任务,这个任务通常不属于标准的项目构建流程,或者是构建流程中的某个具体步骤的独立调用。
- 工作方式: 此命令会绕过生命周期,直接找到指定的插件并执行其提供的特定功能(
goal)。
- 命令格式:
Maven Cordinates

Maven 坐标(Coordinates)是 Maven 用来唯一标识一个项目或依赖的方式。它由以下四个部分组成:
- groupId: 组织或公司标识符,通常是反向域名格式(如
org.apache.maven.plugins) - artifactId: 项目的唯一标识符,通常是项目的名称(如
maven-archetype-plugin) - packaging: 项目的打包方式;通常是
jar、war、pom等 - version: 项目的版本号(如
3.2.0);处于积极开发中的项目可以使用一个特殊的标识符,将版本标记为 SNAPSHOT。
其排列的方式为 groupId:artifactId[:packaging[:version]]
例如 JUnit:junit:jar:4.13.2 代表了 JUnit 4.13.2 版本的 JAR 包。
Maven Repositories
Maven 仓库是用来存储所有项目构件(Artifacts,如 JAR 文件)和插件(Plugins)的地方。Maven 本身安装包之所以很小(约 1.5MB),就是因为它只包含最核心的功能。所有具体的工作(如编译、打包)都由插件完成,而这些插件都是在需要时才从远程仓库下载的。
Maven 仓库的种类
- 远程仓库 (Remote Repository)
- 中央仓库 (Central Repository):Maven 自带一个默认的远程仓库地址 (
https://repo1.maven.org/maven2/),绝大多数开源的库都可以从这里下载。 - 私有/自定义仓库 (Custom Repository):公司或组织可以架设自己的私有仓库,用于存放内部项目或无法公开的商业库。这些私有仓库可以作为中央仓库的补充或镜像。
- 中央仓库 (Central Repository):Maven 自带一个默认的远程仓库地址 (
- 本地仓库 (Local Repository)
- 这是一个位于你自己的电脑上的文件夹(通常在 ~/.m2/repository)
- 作为本地项目间的共享机制和缓存机制
Maven 仓库的目录结构
Maven 仓库不是一个随意的文件夹,它有着非常严格的、标准化的目录结构
按照 /<groupId 的路径>/<artifactId>/<version>/<artifactId>-<version>.<packaging> 的格式来组织文件。
例子:坐标为 org.apache.commons:commons-email:1.1 的 JAR 文件,其存储路径就是 /org/apache/commons/commons-email/1.1/commons-email-1.1.jar,结合中央仓库地址得到:
https://repo1.maven.org/maven2/org/apache/commons/commons-email/1.1/commons-email-1.1.jar