Maven学习笔记

Maven介绍

Maven 是一个 项目管理与构建自动化工具

Maven 解决了软件构建的两方面问题:

  • 一是软件是如何构建的。
  • 二是软件的依赖关系。

Maven 的核心功能包括:

  • 项目构建(编译、测试、打包、部署)
  • 依赖管理(自动下载和管理第三方库)
  • 标准化项目结构(约定优于配置)
  • 插件扩展(支持自定义构建流程)

优势:

  • 减少配置:约定优于配置,减少 build.xml(Ant)这样的手动配置。
  • 依赖自动管理:只需声明依赖,Maven 自动下载并处理冲突。
  • 跨平台:基于 Java,可在 Windows、Linux、macOS 上运行。
  • 与 IDE 集成:Eclipse、IntelliJ IDEA、VS Code 都支持 Maven。

Maven 下载

Maven 下载地址:http://maven.apache.org/download.cgi

不同平台下载对应的包:

系统 包名
Windows apache-maven-3.3.9-bin.zip
Linux apache-maven-3.3.9-bin.tar.gz
Mac apache-maven-3.3.9-bin.tar.gz

新建系统变量 MAVEN_HOME,变量值:E:\Maven\apache-maven-3.3.9

编辑系统变量 Path,添加变量值:;%MAVEN_HOME%\bin

配置 Maven 本地仓库

Maven 默认从远程仓库下载依赖,并存储在本地:

默认本地仓库路径:

  • Windows: C:\Users\<用户名>\.m2\repository
  • Linux/macOS: ~/.m2/repository

修改仓库位置(可选):

在 MAVEN_HOME/conf/settings.xml 中修改:

<localRepository>/path/to/your/repo</localRepository>

创建 Maven 项目

使用 Maven 创建项目

运行以下命令生成标准 Java 项目:

mvn archetype:generate \
-DgroupId=com.example \
-DartifactId=my-first-app \
-DarchetypeArtifactId=maven-archetype-quickstart \
-DinteractiveMode=false

参数说明:

参数 说明
-DgroupId 组织名(如公司域名倒写)
-DartifactId 项目名称(会成为项目文件夹名)
-DarchetypeArtifactId 使用的模板(quickstart 是基础 Java 项目)
-DinteractiveMode=false 非交互模式(避免手动确认)

这会生成一个标准 Maven 项目结构:

my-first-app/
├── pom.xml # Maven 项目配置文件
├── src/
│ ├── main/ # 主代码目录
│ │ └── java/ # Java 源代码
│ │ └── com/example/App.java # 自动生成的示例类
│ └── test/ # 测试代码目录
│ └── java/ # 测试类
│ └── com/example/AppTest.java # 自动生成的测试类

源代码结构

目录 作用
src/main/java 主 Java 源代码
src/main/resources 配置文件(如 application.properties)
src/test/java 测试代码
src/test/resources 测试资源文件

解读 pom.xml

生成的 pom.xml 示例:

<project>
<!-- POM 模型版本,固定 4.0.0 -->
<modelVersion>4.0.0</modelVersion>

<!-- 项目坐标(唯一标识) -->
<groupId>com.example</groupId>
<artifactId>my-first-app</artifactId>
<version>1.0-SNAPSHOT</version>

<!-- 项目打包方式(默认 jar,也可以是 war、pom 等) -->
<packaging>jar</packaging>

<!-- 项目名称和 URL(可选) -->
<name>my-first-app</name>
<url>http://www.example.com</url>

<!-- 依赖管理 -->
<dependencies>
<!-- JUnit 测试依赖 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope> <!-- 仅用于测试 -->
</dependency>
</dependencies>
</project>

常用 Maven 命令

命令 作用
mvn compile 编译源代码
mvn test 运行测试
mvn package 打包(生成 .jar 文件)
mvn install 安装到本地仓库(供其他项目依赖)
mvn clean 清理 target 目录

常见问题

依赖下载失败

原因:网络问题或仓库不可用。

解决方案:

检查网络连接。

配置国内镜像仓库(如阿里云):

<!-- 在 settings.xml 或 pom.xml 中配置 -->
<mirror>
<id>aliyun</id>
<url>https://maven.aliyun.com/repository/public</url>
<mirrorOf>central</mirrorOf>
</mirror>

阿里云仓库介绍:https://developer.aliyun.com/mvn/guide。

编译版本问题

错误:javac: invalid target release: 11

解决方案:在 pom.xml 中指定 Java 版本:

<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>

Maven POM

POM ( Project Object Model,项目对象模型 ) 是 Maven 的核心配置文件,采用 XML 格式,默认命名为 pom.xml。

POM 是 Maven 工程的基本工作单元,是一个 XML 文件,包含了项目的基本信息,用于描述项目如何构建,声明项目依赖,等等。

执行任务或目标时,Maven 会在当前目录中查找 POM,获取所需的配置信息,然后执行目标。

POM 标签大全详解

以下是对 pom.xml 中所有重要标签的分类说明,涵盖 项目信息、依赖管理、构建配置、环境设置 等核心内容。

所有 POM 文件必须包含的标签: modelVersion、groupId、artifactId 和 version。

标签 类别 说明 示例/可选值 是否必需
基础信息
<modelVersion> 项目结构 POM模型版本 4.0.0 是
<groupId> 坐标 组织标识(反向域名) com.example 是
<artifactId> 坐标 项目名称 my-project 是
<version> 坐标 项目版本 1.0.0-SNAPSHOT 是
<packaging> 项目类型 打包格式 jar/war/pom 否(默认jar)
<name> 元信息 项目显示名称 My Application 否
<description> 元信息 项目描述 A demo project 否
<url> 元信息 项目主页URL https://example.com 否
依赖管理
<dependencies> 依赖 依赖列表容器 包含多个<dependency> 否
<dependency> 依赖 单个依赖定义 包含groupId等子标签 可选
<scope> 依赖 依赖作用域 compile/test/provided/runtime 否(默认compile)
<optional> 依赖 是否可选依赖 true/false 否(默认false)
<exclusions> 依赖 排除传递性依赖 包含<exclusion>列表 否
构建配置
<build> 构建 构建配置容器 包含插件/资源等配置 否
<plugins> 构建 插件列表容器 包含多个<plugin> 否
<plugin> 构建 单个插件定义 需指定groupId和artifactId 可选
<resources> 构建 资源文件配置 定义<resource>路径 否
<testResources> 构建 测试资源文件配置 类似<resources> 否
<finalName> 构建 最终打包文件名 my-app 否
环境配置
<properties> 配置 自定义变量容器 定义键值对 否
<java.version> 属性 Java版本变量 11/17等 否
<repositories> 仓库 自定义远程仓库列表 包含<repository> 否
<pluginRepositories> 仓库 自定义插件仓库 类似<repositories> 否
多模块管理
<modules> 模块 子模块列表 包含多个<module> 聚合项目需要
<parent> 继承 父POM引用 需指定父项目坐标 继承项目需要
<dependencyManagement> 依赖 统一管理依赖版本 定义版本但不引入 否
<profiles> 配置 环境profile容器 定义不同环境配置 否
其他信息
<licenses> 法律 许可证信息 包含<license> 否
<developers> 人员 开发者列表 包含<developer> 否
<contributors> 人员 贡献者列表 类似<developers> 否
<issueManagement> 管理 问题跟踪系统 定义issue系统URL 否

Maven 构建生命周期

Maven 构建生命周期定义了一个项目构建跟发布的过程,包含三个标准生命周期:

  • clean:清理项目
  • default(或 build):核心构建流程
  • site:生成项目文档

1、Clean 生命周期:

  • clean:删除目标目录中的编译输出文件。这通常是在构建之前执行的,以确保项目从一个干净的状态开始。

2、Default 生命周期(也称为 Build 生命周期):

  • validate:验证项目的正确性,例如检查项目的版本是否正确。
  • compile:编译项目的源代码。
  • test:运行项目的单元测试。
  • package:将编译后的代码打包成可分发的格式,例如 JAR 或 WAR。
  • verify:对项目进行额外的检查以确保质量。
  • install:将项目的构建结果安装到本地 Maven 仓库中,以供其他项目使用。
  • deploy:将项目的构建结果复制到远程仓库,以供其他开发人员或团队使用。

3、Site 生命周期:

  • site:生成项目文档和站点信息。
  • deploy-site:将生成的站点信息发布到远程服务器,以便共享项目文档。

Maven 构建配置文件

构建配置文件是一系列的配置项的值,可以用来设置或者覆盖 Maven 构建默认值。

使用构建配置文件,你可以为不同的环境,比如说生产环境(Production)和开发(Development)环境,定制构建方式。

配置文件在 pom.xml 文件中使用 activeProfiles 或者 profiles 元素指定,并且可以通过各种方式触发。配置文件在构建时修改 POM,并且用来给参数设定不同的目标环境(比如说,开发(Development)、测试(Testing)和生产环境(Production)中数据库服务器的地址)。

构建配置文件的类型

构建配置文件大体上有三种类型:

类型 在哪定义
项目级(Per Project) 定义在项目的POM文件pom.xml中
用户级 (Per User) 定义在Maven的设置xml文件中 (%USER_HOME%/.m2/settings.xml)
全局(Global) 定义在 Maven 全局的设置 xml 文件中 (%M2_HOME%/conf/settings.xml)

Maven 常用命令

Maven 命令遵循以下模式:

mvn [选项] [生命周期阶段] [目标]

Maven 三大生命周期:clean、default(构建)、site

一、基础生命周期命令

命令 作用
mvn -v 查看 Maven、JDK 版本
mvn clean 清理,删除 target 目录
mvn validate 校验项目结构、pom 是否合法
mvn compile 编译主代码,输出到 target/classes
mvn test-compile 编译测试代码
mvn test 执行单元测试
mvn package 打包(jar/war)
mvn verify 执行集成测试,校验包
mvn install 打包后安装到本地仓库
mvn deploy 上传包到远程私服

生命周期阶段是顺序执行:执行后面阶段会自动执行前面所有阶段。 例:mvn package → 自动执行 validate → compile → test-compile → test → package

二、依赖管理

# 打印依赖树,排查依赖冲突
mvn dependency:tree

# 分析依赖:未声明却使用 / 声明了但没使用
mvn dependency:analyze

# 复制所有依赖 jar 到输出目录
mvn dependency:copy-dependencies

# 清除本地仓库该项目依赖缓存,重新拉取
mvn dependency:purge-local-repository

# 检查依赖有没有新版本
mvn versions:display-dependency-updates

# -U 强制更新快照 SNAPSHOT 依赖(非常常用)
mvn clean install -U

三、测试相关

# 执行全部测试
mvn test

# 跳过测试执行(代码依然编译)
mvn package -DskipTests

# 完全跳过测试编译+执行
mvn package -Dmaven.test.skip=true

# 只运行指定测试类
mvn test -Dtest=UserServiceTest

# 只运行测试类里某个方法
mvn test -Dtest=UserServiceTest#testCreate

四、多模块项目

# -pl:指定模块(只构建service模块)
mvn -pl service clean install

# -am:同时构建该模块依赖的其他模块
mvn -am -pl web clean install

# -rf:从指定模块开始继续构建(构建失败恢复用)
mvn -rf service install

五、插件 & POM 查看

# 查看最终生效的完整 pom(合并父pom、profile)
mvn help:effective-pom

# 查看插件信息
mvn help:describe -Dplugin=compiler

六、创建项目

# 创建普通Java项目
mvn archetype:generate -DgroupId=com.demo -DartifactId=demo-app -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false

# 创建web项目
mvn archetype:generate -DgroupId=com.demo -DartifactId=demo-web -DarchetypeArtifactId=maven-archetype-webapp -DinteractiveMode=false

七、高频组合命令

# 清理 + 编译 + 测试 + 安装到本地仓库
mvn clean install

# 清理打包,跳过测试(本地快速打包)
mvn clean package -DskipTests

# 清理安装,强制更新快照依赖
mvn clean install -U

八、高级参数

# 离线模式,不访问远程仓库,只用本地缓存
mvn -o package

# 开启调试日志,排查构建报错
mvn -X clean install

# -T n 多线程并行构建,n=CPU核心数
mvn -T 4 clean install

# 指定profile环境(开发/测试/生产)
mvn clean install -P prod

九、Maven Site 文档

# 生成项目站点文档
mvn site

Maven 依赖机制

一、核心作用

Maven 自动管理第三方 jar,自动下载依赖、自动引入传递依赖,不用手动拷贝 jar 包。

查找顺序:本地仓库 → 远程私服(如果配置) → Maven 中央仓库

二、Maven 坐标

groupId + artifactId + version,三者定位一个 jar

<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>

三、依赖 Scope 依赖范围

Scope 控制依赖在编译、测试、运行哪个阶段生效,同时影响传递依赖和打包。

scope 生效阶段 是否打入包 说明
compile(默认) 编译、测试、运行 ✅ 核心业务依赖,会传递
provided 编译、测试 ❌ 运行时容器 / JDK 提供(servlet-api)
runtime 测试、运行 ✅ 编译不需要,运行需要(jdbc 驱动)
test 仅测试 ❌ 单元测试,不传递(junit)
system 编译、测试 ❌ 指定本地 jar 路径,不推荐使用

传递规则:只有 compile、runtime 会传递;provided、test 不会向下传递。

四、传递依赖(Transitive Dependency)

A 依赖 B,B 依赖 C → Maven 自动把 C 引入 A 项目。 缺点:容易带来依赖冲突

解决冲突:依赖调解(Dependency Mediation)

两条核心规则:

  1. 最短路径优先:依赖树路径短的版本胜出
  2. 路径长度相同:先声明优先,pom 里靠前的依赖版本生效

排查冲突命令:mvn dependency:tree

五、排除传递依赖 exclusions

不想引入某个传递依赖时使用,不需要写 version

<dependency>
<groupId>com.example</groupId>
<artifactId>example-lib</artifactId>
<version>1.0</version>
<exclusions>
<exclusion>
<groupId>org.unwanted</groupId>
<artifactId>unwanted-jar</artifactId>
</exclusion>
</exclusions>
</dependency>

六、可选依赖 optional

<optional>true</optional>

当前项目依赖这个 jar,但不会传递给依赖自己的上层项目。 区别:exclusions 是主动排除;optional 是声明不传递。

七、dependencyManagement

只统一版本声明,不会自动引入依赖! 父工程 pom:

<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.3.20</version>
</dependency>
</dependencies>
</dependencyManagement>

子模块引用时,只需要 groupId、artifactId,省略 version

<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
</dependency>
</dependencies>

BOM(Bill of Materials)导入

SpringBoot 大量使用,一次性导入一组依赖版本管理

<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.6.4</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>

import scope:只能放在 dependencyManagement 里,导入其他 pom 的版本管理。

八、Maven 仓库

  1. 本地仓库:~/.m2/repository,本机缓存 jar
  2. 远程仓库
    • 中央仓库:Maven 官方默认公共仓库
    • 私服:企业内部 Nexus 仓库(内网,存放公司私有 jar + 代理中央仓库)

仓库配置:settings.xml(用户目录 /maven 安装目录)、pom.xml 均可配置 repositories

九、依赖相关常用命令

# 查看依赖树,定位冲突
mvn dependency:tree

# 分析依赖:声明未使用 / 使用未声明
mvn dependency:analyze

# 复制所有依赖jar到输出目录
mvn dependency:copy-dependencies

# 检查依赖新版本
mvn versions:display-dependency-updates

十、最佳实践

  1. 不要使用 LATEST / RELEASE 动态版本,版本固定,保证构建可复现
  2. 多模块项目统一使用 dependencyManagement + BOM 管理版本
  3. 出现版本冲突:dependency:tree 定位,使用 exclusions 排除
  4. 谨慎使用 system scope 和 optional
  5. 定期执行 dependency:analyze 清理无用依赖

Maven 多模块项目管理

一、概念

Maven 多模块项目由父项目(parent)和多个子模块(submodule)组成。父项目本身不写业务代码,主要负责统一管理版本、依赖、插件,子模块是实际业务代码。

父项目打包类型必须是:<packaging>pom</packaging>

目录结构

parent-project/          # 父工程
├── pom.xml # 父POM,packaging=pom,配置<modules>
├── module-common/ # 公共模块
│ └── pom.xml
├── module-service/ # 业务模块
│ └── pom.xml
└── module-web/ # web模块
└── pom.xml

二、核心配置

1. 父工程 pom.xml

<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>parent-project</artifactId>
<version>1.0.0</version>
<!-- 父工程必须是pom -->
<packaging>pom</packaging>

<!-- 声明所有子模块 -->
<modules>
<module>module-common</module>
<module>module-service</module>
<module>module-web</module>
</modules>

<!-- 统一管理依赖版本,子模块引用无需写version,不会自动引入依赖 -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.example</groupId>
<artifactId>module-common</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
</dependencyManagement>

<!-- 写在这里的dependencies:所有子模块自动继承该依赖 -->
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.30</version>
</dependency>
</dependencies>
</project>

2. 子模块 pom.xml(继承父工程)

<project>
<!-- 指定父工程 -->
<parent>
<groupId>com.example</groupId>
<artifactId>parent-project</artifactId>
<version>1.0.0</version>
<!-- 父pom相对路径,子模块在父目录下时一般不用写 -->
<relativePath>../pom.xml</relativePath>
</parent>

<modelVersion>4.0.0</modelVersion>
<!-- 子模块artifactId,groupId、version默认继承父工程 -->
<artifactId>module-common</artifactId>
</project>

3. 模块之间相互依赖

例如 module-service 依赖 module-common:

<dependencies>
<dependency>
<groupId>com.example</groupId>
<artifactId>module-common</artifactId>
<!-- 因为父工程dependencyManagement声明过,可以省略version -->
</dependency>
</dependencies>

区分两个关键点:

  1. <dependencyManagement>:只锁定版本,不会自动引入依赖,子模块想用需要自己在 dependencies 声明
  2. 父工程直接写在 <dependencies>:所有子模块全部自动继承该依赖

三、多模块构建命令

在父工程目录执行:

# 构建全部子模块,Maven自动根据模块依赖顺序构建
mvn clean install

# -pl 指定只构建某个模块
mvn clean install -pl module-web

# -am:同时构建当前模块依赖的其他模块(最常用)
mvn clean install -pl module-web -am

# -rf:从指定模块开始继续构建(构建失败恢复使用)
mvn clean install -rf module-service
  • -pl = projects list:指定模块列表,逗号分隔多个模块
  • -am = also-make:构建当前模块,同时构建它依赖的模块
  • -rf = resume-from:从指定模块恢复构建

Maven Reactor:负责多模块项目,自动计算模块构建顺序。

四、多模块项目优势

  1. 职责拆分:大型项目分层拆分(common、dao、service、web),便于团队协作
  2. 代码复用:公共代码抽成 common 模块,其他模块引用
  3. 统一管理:统一版本、依赖、插件配置
  4. 按需构建:可以只构建改动模块,提升构建速度

五、常见问题

1. 循环依赖(模块 A 依赖 B,B 依赖 A)

Maven 构建直接报错,不允许模块循环依赖 解决:提取公共代码到第三个公共模块,解耦。

2. 构建顺序问题

Maven Reactor 自动分析模块依赖关系决定构建顺序;如果依赖关系复杂识别错误,可以显式调整。

3. dependencyManagement 和父 dependencies 容易混淆

  • dependencyManagement:版本锁定,按需引入,推荐大型项目使用
  • 父 dependencies:强制全部子模块继承依赖,容易引入多余 jar,慎用

六、最佳实践

  1. 父工程只用 dependencyManagement 统一版本,尽量不要在父 dependencies 写大量依赖,避免依赖泛滥
  2. 公共工具类抽成独立 common 模块
  3. 禁止模块之间循环依赖
  4. 使用 -pl -am 按需构建,提高开发效率
  5. 统一版本号,使用 ${project.version} 引用当前项目版本

Maven 插件

一、核心概念

Maven 本身只是执行框架,所有实际工作全部由插件 (plugin)完成。

  • 插件(Plugin):可扩展组件,一个插件包含多个目标(Goal)
  • 目标 Goal:插件里最小执行单元,代表一个具体任务
  • 生命周期 Phase:构建阶段,只是一个 “钩子 / 接口”,本身不干活,需要绑定插件目标来执行

语法:

mvn 插件前缀:目标名
# 示例
mvn compiler:compile

插件与生命周期关系

Maven 三大生命周期:clean、default、site 每个生命周期由一系列 phase(阶段)组成。 Maven内置绑定:phase 默认绑定好对应的插件 goal。 例: mvn compile → 触发 default 生命周期 compile 阶段 → 自动调用 maven-compiler-plugin:compile

两种执行方式区别:

  1. mvn compile:执行生命周期阶段,自动执行前面所有前置阶段
  2. mvn compiler:compile:直接调用插件目标,不会触发生命周期,只执行这个目标

二、插件坐标

插件和依赖一样,使用 groupId + artifactId + version 唯一标识 官方插件 groupId 固定:org.apache.maven.plugins 示例:

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

三、插件目标绑定(2 种方式)

1. 内置绑定(Maven 自带,无需配置)

生命周期阶段 绑定插件目标
compile maven-compiler-plugin:compile
test maven-surefire-plugin:test
package maven-jar-plugin:jar / maven-war-plugin:war
clean maven-clean-plugin:clean

2. 自定义绑定(pom.xml 手动配置)

通过 <executions> 将插件目标绑定到指定生命周期阶段,可以多次执行同一个插件不同任务

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<executions>
<execution>
<phase>compile</phase> <!--绑定到哪个阶段-->
<goals>
<goal>compile</goal>
</goals>
</execution>
</executions>
<!-- 插件参数配置 -->
<configuration>
<source>11</source>
<target>11</target>
</configuration>
</plugin>
</plugins>
</build>
  • <configuration>:配置插件参数
  • <executions>:可以配置多组执行,每组可指定不同 phase、goal

四、常用 Maven 官方插件

  1. maven-compiler-plugin:编译 Java 代码,目标:compile、testCompile

    配置 source/target 指定 JDK 版本

  2. maven-resources-plugin:复制资源文件(resources、testResources)

  3. maven-surefire-plugin:执行单元测试(test目标)

  4. maven-failsafe-plugin:执行集成测试(integration-test)

  5. maven-jar-plugin:打包 jar,可配置 mainClass 指定程序入口

  6. maven-war-plugin:打包 war 包

  7. maven-assembly-plugin:自定义打包(打包所有依赖,生成可执行完整包)

  8. maven-clean-plugin:clean 阶段,删除 target 目录

  9. maven-install-plugin:install,安装到本地仓库

  10. maven-deploy-plugin:deploy,上传到远程私服

示例:指定 JDK 版本 compiler 插件

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>11</source>
<target>11</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>

五、插件两大分类

  1. Build plugins(构建插件):在构建过程执行,配置在 <build><plugins>
  2. Reporting plugins(报告插件):生成站点文档报告,配置在 <reporting>

六、Mojo

Mojo = Maven Plain Old Java Object

插件目标对应的 Java 类,一个 Mojo 对应一个 Goal。 自定义 Mojo 需要继承AbstractMojo,重写execute()方法,加上@Mojo注解。

@Mojo(name = "greet", defaultPhase = LifecyclePhase.COMPILE)
public class GreetingMojo extends AbstractMojo {
@Parameter(property = "name", defaultValue = "World")
private String name;
public void execute() throws MojoExecutionException {
getLog().info("Hello, " + name + "!");
}
}

七、插件调用方式

  1. 生命周期触发(推荐)
mvn compile
  1. 直接调用插件目标
mvn compiler:compile
  1. 命令行传参覆盖插件配置
mvn compiler:compile -Dmaven.compiler.source=11

Maven Archetype(原型 / 项目模板)

一、什么是 Archetype

archetype 是 Maven 的插件,中文叫原型,本质就是项目模板。 作用:一键生成一套标准化的 Maven 目录结构 + 基础 pom.xml + 示例代码,不用手动建包、建文件夹。

命令:mvn archetype:generate,archetype:generate 是 archetype 插件的目标 goal。

二、内置常用原型

  1. maven-archetype-quickstart:普通 Java 项目(jar 包,最常用)
  2. maven-archetype-webapp:Java Web 项目(war 包,带 web.xml)
  3. 还有很多第三方原型:spring-boot-archetype 等

三、两种创建方式

方式 1:交互式(手动选择,直接执行)

mvn archetype:generate

执行后会交互式一步步输入:

  1. 选择原型编号
  2. 选择原型版本
  3. 填写 groupId、artifactId、version、package
  4. 确认信息,输入 Y,自动生成项目

方式 2:非交互式(脚本化,一次性传参,推荐)

# 普通Java项目 quickstart
mvn archetype:generate \
-DgroupId=com.companyname.insurance \
-DartifactId=health \
-Dversion=1.0-SNAPSHOT \
-DarchetypeArtifactId=maven-archetype-quickstart \
-DinteractiveMode=false
# web项目 webapp
mvn archetype:generate \
-DgroupId=com.example \
-DartifactId=demo-web \
-DarchetypeArtifactId=maven-archetype-webapp \
-DinteractiveMode=false

参数说明:

  • -DinteractiveMode=false:关闭交互,直接创建,不需要手动输入
  • archetypeArtifactId:指定原型模板名称

四、quickstart 生成的标准目录结构

health/
├── pom.xml
└── src
├── main
│ └── java
│ └── com/companyname/insurance
│ └── App.java # 主类main方法
└── test
└── java
└── com/companyname/insurance
└── AppTest.java # JUnit测试类

自动生成的 pom.xml:

  • packaging 默认 jar
  • 默认引入 junit 测试依赖(scope=test)

五、自定义 Archetype

可以自己制作 archetype 模板,把公司统一项目结构、pom 配置、工具类封装成自定义原型,团队所有人统一项目脚手架。

  1. 先做好一个参考项目
  2. 使用 mvn archetype:create-from-project 基于现有项目生成原型
  3. install 到本地仓库,之后就可以用自定义 archetype 创建项目

Maven SNAPSHOT

一、什么是 SNAPSHOT

SNAPSHOT 是快照版本,代表开发中、尚未正式发布的版本。版本号后缀带上 -SNAPSHOT,例如 1.0-SNAPSHOT。

作用:多团队并行开发时,一个模块代码频繁迭代,其他模块可以持续拿到最新开发版,不用每次手动升级版本号。

二、快照版本 vs 正式版本(Release)

类型 示例 拉取逻辑 使用场景
SNAPSHOT(快照) 1.0-SNAPSHOT Maven 构建时会去远程仓库检查是否有更新;本地缓存有快照,也可能拉取新版本 开发阶段,模块间联调
Release(正式版) 1.0 一旦下载到本地仓库,不会再次从远程拉取,版本固定不变 上线、稳定发布,版本不可修改

原理:私服上的 SNAPSHOT 包会自动带上时间戳,例如 data-service-1.0-20261007.083000-1.jar,Maven 识别时间戳获取最新快照。

三、核心参数 -U(—update-snapshots)

默认情况下 Maven 对快照有缓存策略,不一定每次构建都强制拉取最新。 -U 强制 Maven 去远程仓库更新 SNAPSHOT 依赖(面试高频)

mvn clean install -U
mvn clean package -U

四、使用示例

被依赖模块(data-service,快照)

<version>1.0-SNAPSHOT</version>

每次代码提交,执行 mvn deploy 上传到私服,版本号不用改,私服自动覆盖 / 生成带时间戳的快照包。

依赖方模块(app-ui)引用快照

<dependency>
<groupId>data-service</groupId>
<artifactId>data-service</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>

app-ui 团队构建时,Maven 会尝试拉取私服最新的 1.0-SNAPSHOT。

五、SNAPSHOT 优缺点

优点

  1. 多团队并行开发,联调方便,不用频繁修改 pom 版本号
  2. 持续获取最新开发代码,适合开发阶段

缺点

  1. 构建结果不可复现:每次构建拿到的快照包可能不一样,同一个 pom 可能打包出不同产物
  2. 私服存储压力大,快照包会不断累积
  3. 生产环境严禁使用 SNAPSHOT,生产环境必须使用 Release 正式版本

六、最佳实践

  1. 开发环境:模块联调使用 SNAPSHOT;
  2. 测试、生产环境:全部使用 Release 正式版本,禁止快照;
  3. 发布上线前,要把版本去掉 -SNAPSHOT,升级为正式版本;
  4. 拉取最新快照依赖,构建命令带上 -U;
  5. 私服一般会配置快照包自动清理策略,防止磁盘占满。

Maven 自动化构建

一、什么是 Maven 自动化构建

场景:多个项目存在依赖关系。当底层公共模块(bus-core-api)代码更新构建完成后,自动触发依赖它的上层项目(app-web-ui、app-desktop-ui)进行构建,保证上层项目使用最新的依赖包。

结合 SNAPSHOT 快照一起使用:底层模块发布快照,上层项目构建自动拉取最新快照。

二、两种实现方案

方案 1:Maven 插件方式(maven-invoker-plugin)

利用 maven-invoker-plugin 插件,在当前项目构建完成后,自动调用其他项目的 pom 执行构建。 在底层项目 bus-core-api 的 pom.xml 配置插件:

<build>
<plugins>
<plugin>
<artifactId>maven-invoker-plugin</artifactId>
<version>1.6</version>
<configuration>
<debug>true</debug>
<pomIncludes>
<pomInclude>app-web-ui/pom.xml</pomInclude>
<pomInclude>app-desktop-ui/pom.xml</pomInclude>
</pomIncludes>
</configuration>
<executions>
<execution>
<id>build</id>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>

执行命令:

mvn clean package -U

执行流程:

  1. 构建 bus-core-api
  2. bus-core-api 构建成功后,插件自动执行 app-web-ui 的构建
  3. app-web-ui 构建成功后,再执行 app-desktop-ui 的构建

优点:纯 Maven 实现,不需要额外服务

缺点:新增依赖项目,需要修改底层模块 pom,维护麻烦;项目多了 pom 臃肿。

方案 2:CI 持续集成服务器(推荐,企业主流)

代表工具:Hudson(老)、Jenkins、GitLab CI、GitHub Actions 等。 原理:

  1. 代码提交到 Git/SVN,触发 CI 服务器构建底层项目 bus-core-api
  2. bus-core-api 构建成功,自动触发下游依赖项目 app-web-ui、app-desktop-ui 构建
  3. CI 自动拉取最新 SNAPSHOT 依赖,完成构建

优点:

  • 不用修改任何项目 pom.xml
  • 新增下游项目,只需要在 CI 页面配置任务依赖关系
  • 支持流水线、邮件通知、失败告警、多环境发布

    缺点:需要单独部署维护 CI 服务

企业实际开发一般优先使用 CI 流水线,很少用 maven-invoker-plugin。

三、和 SNAPSHOT 的关系

自动化构建 + SNAPSHOT 快照配合使用: 底层模块更新,deploy 上传最新快照到私服;然后自动触发上层项目构建,上层项目构建时通过 -U 拉取最新快照,完成联调验证。

Maven 依赖管理

一、核心概念:传递性依赖

A 依赖 B,B 依赖 C;当项目引入 A,Maven 自动把 B、C 全部引入,这就是传递依赖。 只需要在 pom 写直接依赖,Maven 自动解析整个依赖树,不用手动写所有底层 jar。

缺点:依赖树膨胀,容易出现版本冲突。Maven 提供一套机制管控传递依赖。

二、Maven 处理依赖冲突:依赖调节

  1. 最短路径优先原则:依赖在依赖树中的路径越短,版本优先被选中。
  2. 路径深度相同时,先声明优先:同一深度,pom 中先写的依赖版本生效。

举例:项目直接引入 log4j 2.0;同时 A 依赖 log4j 1.0。项目到 2.0 深度是 1,到 1.0 深度是 2 → 选 2.0。

三、依赖管理五大控制手段

  1. dependencyManagement(依赖管理) 统一锁定依赖版本,不会自动引入依赖;子模块使用时,只写 groupId、artifactId,不用写 version。多用于父工程统一管理版本。
  2. scope 依赖范围 限制依赖生效的阶段,控制传递依赖是否向下传递。
scope 作用范围 是否参与打包 传递特性
compile(默认) 编译、测试、运行都有效 ✅ 会传递
test 仅测试编译、测试运行(JUnit) ❌ 不传递
provided 编译需要;运行时由容器 / JDK 提供(servlet-api) ❌ 不传递
runtime 编译不需要,运行时需要(JDBC 驱动) ✅ 会传递
system 本地系统路径 jar,不推荐 - 会传递
import 仅用在 dependencyManagement,导入外部 pom 的依赖版本 - 不传递
  1. exclusions 依赖排除 手动排除传递依赖,解决冲突。
<dependency>
<groupId>A</groupId>
<artifactId>A-core</artifactId>
<version>1.0</version>
<exclusions>
<exclusion>
<groupId>B</groupId>
<artifactId>B-lib</artifactId>
</exclusion>
</exclusions>
</dependency>

含义:引入 A,但不引入 A 自带的传递依赖 B。

  1. optional 可选依赖 B 依赖 C,在 B 中把 C 标记<optional>true</optional>;当 A 依赖 B 时,C 不会传递到 A。

区别:exclusion 是使用者去排除;optional 是提供者主动标记不向下传递。

四、父工程统一依赖示例

Root 父工程 packaging=pom

<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.companyname.groupname</groupId>
<artifactId>Root</artifactId>
<version>1.0</version>
<packaging>pom</packaging>

<!-- 子模块全部自动继承 -->
<dependencies>
<dependency>
<groupId>com.companyname.groupname1</groupId>
<artifactId>Lib1</artifactId>
<version>1.0</version>
</dependency>
</dependencies>

<!-- 仅锁定版本,子模块按需引入,不会自动继承 -->
<dependencyManagement>
<dependencies>
</dependencies>
</dependencyManagement>
</project>

区分重点: <dependencies>:写在父 pom,所有子模块自动继承该依赖 <dependencyManagement>:只定义版本,不会自动引入依赖,子模块需要自己声明 dependencies

五、常用命令查看依赖树

# 打印完整依赖树,排查版本冲突
mvn dependency:tree

Maven 自动化部署

一、什么是 Maven 自动化部署

传统手动部署流程:代码提交 SVN/Git → 拉源码 → 构建打包 → 上传构件到私服 → 部署到服务器,多团队人工操作容易出错、版本混乱。

自动化部署整套方案组合

  1. 源码仓库:SVN / Git(管理源代码、打版本标签)
  2. Maven:项目构建
  3. 制品仓库:Nexus / JFrog Artifactory(存放 jar/war 等二进制构件)
  4. maven-release-plugin:Maven 发布插件,一键完成版本升级、打标签、提交、部署到私服

二、pom 中核心配置节点

<!-- SCM:源码仓库配置,Git/SVN地址,用于release插件操作代码仓库 -->
<scm>
<connection>scm:svn:http://xxx/svn/project</connection>
<developerConnection>scm:svn:账号密码@xxx</developerConnection>
</scm>

<!-- distributionManagement:构件分发目标仓库,release插件deploy时上传到此 -->
<distributionManagement>
<repository>
<id>Core-API-Java-Release</id>
<url>http://localhost:8081/nexus/content/repositories/Core-Api-Release</url>
</repository>
</distributionManagement>

<!-- release插件 -->
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-release-plugin</artifactId>
<version>2.0-beta-9</version>
<configuration>
<goals>deploy</goals>
</configuration>
</plugin>
</plugins>
</build>

三、maven-release-plugin 核心目标(goal)

  1. mvn release:clean 清理 release 发布过程产生的临时文件,重置发布环境。
  2. mvn release:prepare 准备发布 执行一系列动作:
  • 检查本地有没有未提交代码
  • 校验项目依赖不能存在 SNAPSHOT 快照
  • 修改 pom:版本从1.0-SNAPSHOT → 1.0(正式版本)
  • 提交 pom 修改到 SCM
  • 在 SVN/Git 上给代码打版本标签 tag
  • 再次修改 pom:版本升级为下一个快照版本(如1.1-SNAPSHOT),提交到 SCM
  • 执行项目测试,验证构建正常
  1. mvn release:perform 执行发布
  • 检出刚才打好 tag 的源码
  • 执行构建打包,执行 deploy,把正式版构件上传到 Nexus/JFrog 私服 Release 仓库
  1. mvn release:rollback 回滚发布 发布过程中途失败,用来撤销 release:prepare 对 pom 的修改、撤销 SCM 提交,回退到发布前状态。

完整发布顺序:release:clean → release:prepare → release:perform 发布失败:release:rollback

四、SNAPSHOT 与 Release 版本在发布中的变化

开发阶段版本:1.0-SNAPSHOT release:prepare 时:

  1. 临时改成 1.0(Release 正式版),打 tag,打包上传到私服 release 仓库
  2. 自动把 pom 版本升级为 1.1-SNAPSHOT,提交代码,供后续开发迭代

五、企业实际使用说明

  1. maven-release-plugin 适合库项目(jar 包)发布到制品仓库;
  2. 应用部署到 Tomcat / 容器服务器,一般不会只用 Maven 直接部署到应用服务器;
  3. 现代企业更多结合 CI (Jenkins/GitLab CI) 流水线,代替手动敲 release 命令;
  4. Release 仓库不允许覆盖构件,版本一旦发布不能修改;Snapshot 仓库可以不断覆盖快照包。

Maven Web 应用

一、创建 Maven Web 项目

使用原型 maven-archetype-webapp 快速生成 Java Web 项目(war 包项目)

mvn archetype:generate \
-DgroupId=com.companyname.automobile \
-DartifactId=trucks \
-DarchetypeArtifactId=maven-archetype-webapp \
-DinteractiveMode=false

二、Web 项目目录结构

trucks
├── pom.xml
└── src
└── main
└── webapp # web应用根目录
├── index.jsp
└── WEB-INF
└── web.xml # web部署描述符

重点:packaging = war,代表打包产物是 war 包。

pom.xml 核心内容

<modelVersion>4.0.0</modelVersion>
<groupId>com.companyname.automobile</groupId>
<artifactId>trucks</artifactId>
<packaging>war</packaging>
<version>1.0-SNAPSHOT</version>
<name>trucks Maven Webapp</name>

<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<finalName>trucks</finalName> <!-- 打包后war文件名 -->
</build>

三、构建 Web 应用

mvn clean package

执行流程:

  1. clean:清空 target 目录
  2. 编译资源、源码
  3. 执行单元测试
  4. war 插件打包,在target目录生成 trucks.war

四、部署 Web 应用

  1. 把 target 下的trucks.war复制到 Tomcat 的webapps目录
  2. 重启 Tomcat
  3. 访问:http://localhost:8080/trucks/index.jsp

五、常用扩展插件

  1. tomcat-maven-plugin:直接通过 mvn 命令启动 tomcat,不用手动复制 war 包
mvn tomcat:run
  1. jetty 插件,本地快速调试 web 项目