maven基本使用-202509120152
maven基本使用
maven基本使用
maven介绍
什么是maven
maven是一个 优秀的构建工具
什么是构建
开发编写的是源代码,然而运行需要的是可执行文件或可部署的应用程序。
maven作为构建工具是将java源代码变成可运行的文件,比如jar包或者war包
这其中的构建步骤包括,编译,依赖管理(下载依赖,使用正确的依赖版本),运行测试,打包
等。
为什么要使用maven
早期的构建工具的弊病
早期的构建工具:make,ant
make与ant没有内置的依赖管理,无标准的生命周期,无标准目录结构,构建规则,需要自己编
写繁琐的配置文件
maven的优点
maven,统一的目录结构,统一的构建过程,无需定义,直接使用
通过仓库统一管理依赖,有丰富的插件提供额外的功能
坐标与依赖
声明项目的maven坐标
Maven 坐标的组成部分
Maven 坐标由以下五个主要部分组成:
groupId(组 ID):
定义:用于标识项目的组织或公司,通常采用反向域名命名法。例如,com.example.pr
oject 。
作用:用于区分不同组织或公司的项目,确保坐标的唯一性。
artifactId(工件 ID):
定义:用于标识项目的具体模块或工件,通常是项目的名称。例如,spring-core 。
作用:区分同一组织或公司下的不同项目或模块。
version(版本):
定义:用于标识项目的版本号。例如,1.0.0 、2.1.5.RELEASE 。
作用:区分同一工件的不同版本,确保依赖的版本一致性。
packaging(打包类型):
定义:指定项目的打包类型,如 jar 、war 、pom 、ear 等。默认情况下,Maven
使用 jar 作为打包类型。
作用:指示 Maven 如何打包项目。例如,jar 用于库,war 用于 Web 应用程序,po
m 用于父 POM 或聚合项目。
classifier(分类器,可选):
定义:用于区分同一版本、同一打包类型的不同构建产物。例如,javadoc 、source
s 等。
作用:在某些情况下,一个项目可能生成多个不同的构建产物,分类器用于区分这些产物。
坐标的命名规范
groupId:通常采用反向域名命名法,例如 com.example.project 。这有助于避免命名
冲突。
artifactId:通常是小写字母,使用中划线(-)分隔单词,例如 my-app 。
version:遵循语义化版本控制(Semantic Versioning),例如 1.0.0 、2.1.5.RELEAS
E 。
packaging:使用标准的打包类型,如 jar 、war 、pom 等。
依赖的引入
依赖范围
compile :默认范围,适用于大多数情况,依赖项在所有阶段都可用。
编译时:依赖项在编译源代码时需要。
测试时:依赖项在编译和运行测试代码时需要。
运行时:依赖项在运行时需要。
provided :依赖项在编译和测试时需要,但在运行时由外部环境提供。
例如,Servlet API 通常设置为 provided ,因为它由应用服务器在运行时提供。
runtime :依赖项在运行时需要,但在编译时不需要。
适用场景:
动态加载的库:例如,JDBC 驱动在编译时只需要接口,但在运行时需要具体的实
现,比如mysql-connector-java。
test :依赖项仅在测试阶段需要,不影响主应用程序的类路径。
适用场景:
测试框架和工具:例如,JUnit、Mockito、Spring Test 等。
system :依赖项需要显式指定路径,不推荐使用。
特定路径的本地库:需要通过 systemPath 属性显式指定依赖项的路径
import :用于导入其他 POM 的依赖管理配置,不引入实际依赖。
依赖传递
什么是依赖传递
依赖传递 是指当您在一个 Maven 项目中声明一个直接依赖时,Maven 会自动解析并引入该依赖
所依赖的所有其他库。这些被自动引入的依赖被称为 传递性依赖。
这个机制极大地方便了依赖管理,但也带来了冲突的可能。
示例:
假设您的项目依赖于 spring-core ,而 spring-core 又依赖于 commons-loggin
g 。通过依赖传递,Maven 会自动将 commons-logging 作为项目的传递性依赖引入,而无
需您手动在 pom.xml 中声明它。
依赖范围(Scope)与传递性
依赖调解(多依赖中都有, 用哪个)
Maven 使用以下优先顺序进行依赖调解:
1. 最短路径优先(Nearest wins)
哪个依赖离根项目路径更短,哪个优先。
“路径”指的是依赖传递链的深度。
示例:
⇒ 选择 B:2.0(路径短)
2. 路径长度相同,先声明者优先(First declared wins)
如果两个依赖路径长度相同,则选择在 pom.xml 中先声明的那个依赖链对应的版本。
3. dependencyManagement 显式指定版本(显式覆盖)
如果你在
自动解析的版本,无论路径长短。
后续引入,省略version即使用dependencyManagement版本
Scope
是否传递
是否参与编译
compile
✅
✅
runtime
✅
❌(自身不可用)但运行时
可用
test
❌
❌(仅测试时可见)
provided
❌
✅(编译可见,打包不包含)
system
❌
✅
├── A(依赖 B:1.0) → 距离2
└── B:2.0 → 距离1
可选依赖
在 Maven 中,可选依赖(optional dependency) 是用来告诉使用你这个库的项目:“我依赖了
这个模块,但你不必一定也去引入它”。它的核心作用就是阻断传递——当一个依赖被标记为 opti
onal 后,Maven 不会把它及其传递依赖自动带给上层项目。下面分几点来分析:
定义
在
默认值:如果不写
传递性:只影响到依赖你的项目的上层消费方,不影响当前模块自己。
依赖冲突
什么是依赖冲突
依赖冲突是指项目中同一个库存在多个不同版本或重复引入的情况cnblogs.comblog.csdn.net。
这通常发生在项目有多条依赖链时,例如显式依赖 A→X(1.0) 和 B→X(2.0) 同时存在时,Maven
必须选择其中一个版本,否则会导致类找不到或方法缺失的错误cnblogs.comblog.csdn.net(如
典型的 NoClassDefFoundError 、NoSuchMethodError )。
依赖冲突的产生原因
Maven 依赖冲突常因以下原因产生:
传递性依赖:Maven 自动引入依赖的依赖。例如项目依赖 A,A 依赖 B,B 依赖 C,层层传
递会产生大量隐式依赖cnblogs.comcnblogs.com。当多个传递路径引入同一库但版本不同
时,就会发生冲突cnblogs.comcnblogs.com。
多模块项目冲突:在多模块项目中,各模块依赖不同版本,最终聚合时依赖合并,引发冲
突blog.csdn.net。例如工程1依赖C:2.1,工程2依赖C:2.2,合并后可能产生版本冲突,需要
统一版本并全面测试blog.csdn.net。
开发者解决依赖冲突的方法
针对依赖冲突,开发者可以采取以下方法来分析和解决问题:
使用 mvn dependency:tree 或 IDE 插件查看依赖树。该命令或工具可以列出项目的所
有依赖(包括传递依赖),并标记出冲突的版本,从而定位冲突源。
在
引入该依赖的 POM 块里添加
如:
如上所示,通过
本。
明确指定所需版本。如果项目依赖中出现多个版本,可以在自己的 POM 中显式指定所需依
赖的版本,从而保证 Maven 选用正确的版本。例如直接在 POM 中添加
指定所需版本,使其优先于传递依赖。
使用
借助辅助工具:使用 Maven Enforcer 插件 的 dependencyConvergence 规则可强制检
查依赖版本一致性。该插件能在构建时报告版本冲突,帮助快速定位问题。此外,IDE 插件
(如 Maven Helper)也可可视化冲突并提供排除建议。
依赖冲突解决案例
你的项目引入两个库:
而 some-library 的 POM 文件中依赖了:
但 spring-boot-starter-web 间接依赖的是:
方法 1:使用
优先级高于传递依赖指定的依赖版本
这样可以统一所有模块使用的 log4j-api 版本,无论哪个库引入。
方法 2:排除冲突依赖(
如果你明确知道只想使用 Spring Boot 的 log4j-api,可以排除掉 some-library 中的 log4j 依
赖:
log4j-api:2.14.1
生命周期与插件
Maven 的生命周期是抽象的,这意味着生命周期本身不做任何实际的工作
再maven 的设计中,实际的任务(如编译源代码)都交由插件来完成
每个构建步骤都可以绑定一个或者多个插件行为
Maven 生命周期的组成
Maven 生命周期由一系列阶段(Phases)组成,每个阶段都有特定的任务。阶段是按顺序执行
的,每个阶段可以绑定一个或多个插件目标(Plugin Goals)。插件目标是实际执行构建任务的代
码片段。
例如,compile 阶段通常绑定到 maven-compiler-plugin 的 compile 目标,用于
编译项目的源代码。
3套生命周期
1. default 生命周期
default 生命周期是 Maven 最主要的生命周期,它定义了从清理项目到最终部署的完整构建
过程。以下是 default 生命周期的主要阶段及其功能:
表格
复制
阶段名称
描述
validate
验证项目是否正确,所有必要的信息是否可
用。
initialize
初始化构建过程,设置构建所需的属性和资
源。
generate-sources
生成源代码文件(如通过代码生成工具生成的
代码)。
process-sources
处理源代码文件,例如过滤资源文件或进行代
码风格检查。
generate-resources
生成资源文件(如配置文件、模板文件等)。
process-resources
复制并处理资源文件到目标目录,准备打包。
compile
编译项目的源代码到目标目录,生成class文
件到target。
process-classes
处理编译后的类文件,例如进行字节码增强。
generate-test-sources
生成测试用例的源代码。
process-test-sources
处理测试用例的源代码。
generate-test-resources
生成测试用例所需的资源文件。
process-test-resources
复制并处理测试用例的资源文件到目标目录。
test-compile
编译测试用例的源代码到目标目录。
process-test-classes
处理编译后的测试用例类文件。
test
运行测试用例,并生成测试报告。
prepare-package
执行打包前的准备工作,例如处理资源文件。
package
将编译后的代码打包成可分发的格式(如 JA
R、WAR)到target目录。
pre-integration-test
在集成测试之前执行的任务,例如设置测试环
境。
integration-test
执行集成测试。
post-integration-test
在集成测试之后执行的任务,例如清理测试环
境。
verify
验证集成测试的结果,确保项目满足质量标
准。
2. clean 生命周期
clean 生命周期用于清理项目,删除之前构建生成的文件。它包含以下阶段:
表格
复制
通常,用户会直接运行 mvn clean 命令来清理项目。
3. site 生命周期
site 生命周期用于生成项目的站点文档,通常用于项目报告和文档生成。它包含以下阶段:
表格
复制
install
将项目安装到本地仓库,供其他项目依赖。
deploy
将项目部署到远程仓库,供其他开发者或项目
使用。
阶段名称
描述
pre-clean
在清理项目之前执行的任务。
clean
删除目标目录(通常是 target 目录)中
的所有文件。
post-clean
在清理项目之后执行的任务。
阶段名称
描述
pre-site
在生成站点之前执行的任务。
site
生成项目的站点文档。
post-site
在生成站点之后执行的任务。
site-deploy
将生成的站点文档部署到服务器。
用户可以通过运行 mvn site 命令生成站点文档,通过 mvn site-deploy 命令将站点文
档部署到服务器。
命令行与生命周期
从命令行执行 Maven 任务的最主要方式就是调用 Maven 的生命周期阶段。需要注意的 是,各个生
命周期是相互独立的,而一个生命周期的阶段是有前后依赖关系的。下面以一 些常见的Maven 命
令为例,解释其执行的生命周期阶段:·
1. $mvn clean:该命令调用 clean 生命周期的clean 阶段。实际执行的阶段为clean 生命 周期的
pre-clean 和 clean 阶段。
2. $mvn test: 该命令调用 default 生命周期的test 阶段。实际执行的阶段为default 生命 周期的
validate initialize 等,直到 test 的所有阶段。这也解释了为什么在执行测试的时候,项目的代码
能够自动得以编译。
3. $mvn clean install:该命令调用 clean 生命周期的clean 阶段和 default 生命周期的install 阶
段。实际执行的阶段为clean 生命周期的pre-clean、clean 阶段,以及default 生 命周期的从 v
alidate 至 install 的所有阶段。该命令结合了两个生命周期,在执行真正 的项目构建之前清理
项目是一个很好的实践。
插件目标
对于插件本身,为了能够复用代码,它往往能够完成多个任务。例如 maven-dependen- cy-plugin,它
能够基于项目依赖做很多事情。它能够分析项目依赖,帮助找出潜在的无用依 赖;它能够列出项目
的依赖树,帮助分析依赖来源;它能够列出项目所有已解析的依赖, 等等。为每个这样的功能编写一
个独立的插件显然是不可取的,因为这些任务背后有很多 可以复用的代码,因此,这些功能聚集在一
个插件里,每个功能就是一个插件目标。
maven-dependency-plugin 有十多个目标,每个目标对应了一个功能,上述提到的几个功 能分别对
应的插件目标为 dependency: analyze dependency: tree 和 dependency: list。这是一种 通用的写
法,冒号前面是插件前缀,冒号后面是该插件的目标。类似地,还可以写出 compiler compile(这是ma
ven-compiler-plugin 的 compile 目标)和 surefire; test (这是maven-surefire-plugin 的 test 目标)。
插件绑定
Maven 的生命周期与插件相互绑定,用以完成实际的构建任务
为了能让用户几乎不用任何配置就能构建 Maven 项目,Maven 在核心为一些主要的生 命周期阶段
绑定了很多插件的目标,当用户通过命令行调用生命周期阶段的时候,对应的 插件目标就会执行相
应的任务。
default生命周期中插件绑定关系
阶段
默认绑定的插件
目标
主要任务
validate
无默认插件(maven
本身来实现)
-
验证项目是否正确,
所有必要的信息是否
可用。
initialize
无默认插件
-
初始化构建过程,设
置构建所需的属性和
资源。
generate-sourc
es
maven-apt-plug
in
process
生成源代码文件(如
通过注解处理器生成
的代码)。
process-source
s
无默认插件
-
处理源代码文件,例
如过滤资源文件或进
行代码风格检查。
generate-resou
rces
无默认插件
-
生成资源文件(如配
置文件、模板文件
等)。
process-resour
ces
maven-resource
s-plugin
resources
复制并处理资源文件
到目标目录,准备打
包。
compile
maven-compiler
-plugin
compile
编译项目的源代码到
目标目录。
process-classe
s
无默认插件
-
处理编译后的类文
件,例如进行字节码
增强。
generate-test-
sources
无默认插件
-
生成测试用例的源代
码。
process-test-s
ources
无默认插件
-
处理测试用例的源代
码。
generate-test-
resources
无默认插件
-
生成测试用例所需的
资源文件。
process-test-r
esources
maven-resource
s-plugin
testResources
复制并处理测试用例
的资源文件到目标目
录。
自定义绑定
自定义绑定通过在 pom.xml 文件中配置插件来实现。用户需要指定插件的 groupId 、ar
tifactId 、version ,以及要绑定的生命周期阶段和目标。
test-compile
maven-compiler
-plugin
testCompile
编译测试用例的源代
码到目标目录。
process-test-c
lasses
无默认插件
-
处理编译后的测试用
例类文件。
test
maven-surefire
-plugin
test
运行测试用例,并生
成测试报告。
prepare-packag
e
无默认插件
-
执行打包前的准备工
作,例如处理资源文
件。
package
根据项目类型(如 m
aven-jar-plugi
n 或 maven-war-
plugin )
package
将编译后的代码打包
成可分发的格式(如
JAR、WAR)。
pre-integratio
n-test
无默认插件
-
在集成测试之前执行
的任务,例如设置测
试环境。
integration-te
st
无默认插件
-
执行集成测试。
post-integrati
on-test
无默认插件
-
在集成测试之后执行
的任务,例如清理测
试环境。
verify
无默认插件
-
验证集成测试的结
果,确保项目满足质
量标准。
install
maven-install-
plugin
install
将项目安装到本地仓
库,供其他项目依
赖。
deploy
maven-deploy-p
lugin
deploy
将项目部署到远程仓
库,供其他开发者或
项目使用。
案例
使用 protobuf-maven-plugin 插件来编译 .proto 文件,并生成 Java 代码,同时支持
gRPC 和 Dubbo 的代码生成
没有明确指定phase,使用默认的phase
指定目标compile和compile-custom
ssifier}
java:1.58.0:exe:${os.detected.classifier}
命令行插件配置
在日常的Maven 使用中,我们会经常从命令行输入并执行 Maven 命令。
。很多插件目标的参数都支持从命 令行配置,用户可以在 Maven 命令中使用-D参数,并伴随一个参
数键=参数值的形式,来 配置插件目标的参数。
例如,maven-surefire-plugin 提供了一个 maven. test. skip 参数,当其值为true 的时候,就 会跳过执
行测试。
于是,在运行命令的时候,加上如下-D 参数就能跳过测试:
参数-D是Java 自带的,其功能是通过命令行设置一个Java 系统属性,Maven 简单地重 用了该参数,
在准备插件的时候检查系统属性,便实现了插件参数的配置。
maven中pom解析
deliver项目的start-deliver
starter.version}
$ mvn install-Dmaven.test.skip =true
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/maven-v4_0_0.xsd">
starter
-
javaagent:${settings.localRepository}/org/jmockit/jmockit/1.49/jmockit-
1.49.jar
rsion}.jar
可能的优化
在setting.xm中使用profile并激活,设置属性
在pom中读取
通过添加skip属性是否跳过,当env.dev为true跳过
没有或者为false不跳过
infrastructure/src/main/resources
自定义maven插件
可以通过maven插件对应的archetype来创建maven插件项目
它创建的项目打包方式为maven-plugin
编写插件的对应代码
只需要一个类就可以实现一个基本的goal,执行日志输出
rsion}.jar
mvn archetype:generate \
-DgroupId=com.example.maven \
-DartifactId=my-maven-plugin \
-Dversion=1.0.0 \
-DarchetypeGroupId=org.apache.maven.archetypes \
-DarchetypeArtifactId=maven-archetype-plugin \
-DinteractiveMode=false
引入自己的插件
结果
在package阶段有日志输出
/**
*/
@Mojo( name = "touch", defaultPhase = LifecyclePhase.PROCESS_SOURCES )
public class MyMojo
extends AbstractMojo
{
public void execute()
throws MojoExecutionException
{
getLog().info("Hello this is my-maven-plugin,and this is
goal:touch");
}
}
touch
[INFO]
[INFO] --- myMavenPlugin:1.0-SNAPSHOT:touch (default) @ mavenPractice -
--
[INFO] Hello this is my-maven-plugin,and this is goal:touch
[INFO]
archetype
什么是 Maven Archetype?
Archetype 是 Maven 的项目生成器。
Archetype 是通过插件来实现的,这一插件是maven-archetype-plugin
archetype项目
Archetype:字面意思为“原型”或“模板”。在 Maven 中,一个 Archetype 项目其实就是一个预先
配置好的 Maven 项目模板,它定义了目录结构、依赖、插件配置以及默认的代码文件。
使用场景:当你需要新建一个项目时,可以通过 Maven 的 archetype:generate 命令,从
现有的 Archetype 模板中生成一个新的项目,这个新项目会继承模板中定义的结构和配置。常见
的 Archetype 例如 maven-archetype-quickstart (标准 Java 项目模板)、maven-arc
hetype-webapp (Web 应用模板)等。
打包方式
使用archetype创建cola项目
使用archetype插件,generate为goal,-D后面是参数
使用的项目模板为cola-framework-archetype-web
课后题目
✅ 1. Maven 的默认生命周期中,哪个阶段会执行单元测试?
A. compile
B. validate
C. test
D. package
mvn archetype:generate \
-DgroupId=com.alibaba.cola.demo.web \
-DartifactId=demo-web \
-Dversion=1.0.0-SNAPSHOT \
-Dpackage=com.alibaba.demo \
-DarchetypeArtifactId=cola-framework-archetype-web \
-DarchetypeGroupId=com.alibaba.cola \
-DarchetypeVersion=5.0.0
答案:C
解析: test 阶段会执行由 src/test/java 中的测试代码构成的单元测试。
✅ 2. Maven 如何解决依赖冲突?
A. 根据依赖声明顺序选择
B. 优先使用最新版本
C. 最近优先原则(Nearest wins)
D. 自动禁用冲突依赖
答案:C
解析: Maven 采用 最近优先 原则,路径更短(离项目更近)的依赖版本会被采用。
✅ 3. 下列哪个元素可用于控制插件是否执行?
A.
B.
C.
D.
答案:C
解析: 多数 Maven 插件支持
ugin 、surefire-plugin 等。
✅ 4. Maven 的哪个标签可以统一管理子模块依赖版本?
A.
B.
C.
D.
答案:B
解析:
可。
✅ 5. Maven 的哪个配置文件用于存储用户级别的配置?
A. pom.xml
B. settings.xml
C. build.xml
D. project.xml
答案:B
解析: settings.xml 是 Maven 的全局或用户级别配置文件,通常位于 ~/.m2/ 目录。
✅ 6. 如何在 Maven 中定义并激活一个构建环境?
A. 使用
B. 使用
C. 使用
D. 使用
答案:C
解析: Maven 通过
动或手动激活。
✅ 7. Maven 默认的本地仓库位置是?
A. /usr/maven/repository
B. C:.maven\lib
C. ~/.m2/repository
D. ~/.repository
答案:C
解析: 默认仓库为 ~/.m2/repository ,也可以在 settings.xml 中自定义。
✅ 8. 以下哪个命令可以生成项目骨架?
A. mvn install
B. mvn generate
C. mvn archetype:generate
D. mvn structure:create
答案:C
解析: mvn archetype:generate 是用来生成 Maven 项目结构的标准命令。