Maven
Maven是一款基于Java平台的项目管理和整合工具,他将项目的开发和管理过程抽象成一个项目目标对象模型。
简介
maven使用Java语言编写,因此和Java一样具有跨平台性;maven使用标准的目录结构和默认构建生命周期,开发者可以非常简单的完成项目的基础构建工作
maven能够帮助开发者完成以下任务:
- 构建项目
- 生成文档
- 创建报告
- 维护依赖
- 软件配置管理
- 发布
- 部署
约定优于配置是Maven最核心的涉及理念之一,maven对项目的目录结构,测试用例命名方式等内容都做了规定,凡是使用Maven管理的项目都必须遵守这些规则
文件 | 目录 |
---|---|
Java 源代码 | src/main/java |
资源文件 | src/main/resources |
测试源代码 | src/test/java |
测试资源文件 | src/test/resources |
打包输出文件 | target |
编译输出文件 | target/classes |
POM
POM(Project Object Model,项目对象模型)是Maven的基本组件,它是以pom.xml文件的形式存放在项目的根目录下
pom中可以设置如下配置:
- 项目依赖
- 插件
- 目标
- 构建时的配置文件
- 版本
- 开发者
- 邮件列表
groupId
工程组,artifactId
名称,version
版本这些属性是项目的唯一标识
节点 | 描述 |
---|---|
groupId | 项目组 ID,定义当前 Maven 项目隶属的组织或公司,通常是唯一的。它的取值一般是项目所属公司或组织的网址或 URL 的反写,例如 net.biancheng.www。 |
artifactId | 项目 ID,通常是项目的名称。groupId 和 artifactId 一起定义了项目在仓库中的位置。 |
version | 项目版本。 |
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.henrik</groupId>
<artifactId>maven</artifactId>
<version>0.0.1-SNAPSHOT</version>
</project>
effective pom:所有的POM均继承自一个父POM,这个父POM被称为Super POM,Maven使用effective pom
(Super POM)的配置加上项目的配置来执行相关任务,它替开发人员在pom.xml中做了一些最基本的配置,开发者可以根据需要重写其中的配置信息,通过在pom文件的目录下执行以下命令,就可以查看Super POM的默认配置。实际开发中,Maven的pom.xml文件不需要手工编写,Maven提供了大量的原型(Archetype)插件来创建项目,包括项目结构和pom.xml
mvn help:effctive-pom
仓库
构件:任何一个依赖,插件或者项目构建的输出,都可以称为构件
仓库:统一存储所有项目构件的位置
本地仓库:通过setting.xml
文件中localRepository
元素进行定义
命令,坐标,依赖
1.命令
(1).clean:负责清理target目录
(2).package:负责将项目构建并打包输出为jar文件
(3).compile:对项目重新进行编译
2.坐标
世界上任何一个构件都可以使用Maven坐标并作为其唯一标识,Maven坐标包括groupId
,artifactId
,version
,packaging
(默认值为jar,是可选的)等元素,只要用户提供正确的坐标元素,Maven就能找到相应的构件
3.依赖
所有的Maven项目必须明确定义自己的坐标,只有这样,它们才可以成为其他项目的依赖。当Maven项目需要声明某个依赖时,通常只需要在其POM中配置该依赖的坐标信息,Maven会根据坐标自动将依赖下载到项目中
<dependencies>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
</dependencies>
每个依赖可以包含以下元素
- groupId,artifactId,vesion:依赖的基本坐标
- type:依赖的类型,对应于项目坐标定义的packaging
- scope:依赖的范围
- optional:标记依赖是否可选
- exclusions:用来排除传递性依赖
4.导入本地jar包
某个项目需要依赖存储在本地的某个jar包,这种依赖被称为外部依赖或本地依赖
<dependencies>
<!-- 外部依赖 -->
<dependency>
<groupId>henrik</groupId>
<artifactId>henrik</artifactId>
<!-- 依赖范围 --->
<scope>system</scope>
<version>1.0-SNAPSHOT</version>
<!-- 依赖所在位置 -->
<systemPath>D:\maven\henrik\target\henrik-1.0-SNAPSHOT.jar</systemPath>
</dependency>
</dependencies>
- scope表示依赖范围,这里取值必须是system,即系统
- systemPath表示依赖的本地构件的位置
依赖传递
依赖传递是Maven的核心机制之一,它一定程度上简化Maven的依赖配置。
如果项目A
依赖于项目B
,B
又依赖项目C
,此时B
是A
的直接依赖,c
是A
的间接依赖。
依赖传递机制:不管Maven项目存在多少间接依赖,POM中都只需要定义其直接依赖,Maven会自动读取当前项目各个直接依赖的POM,将那些必要的间接依赖以传递性依赖的形式引入到当前项目中
通过传递依赖会使依赖关系迅速增长到一个很大的量级,很可能会出现依赖重复,依赖冲突等情况,Maven针对这些情况提供了如下功能进行处理
- 依赖范围(Dependency scope)
- 依赖调解(Dependency mediation)
- 可选依赖(Optional dependencies)
- 排除依赖(Excluded dependencies)
- 依赖管理(Dependency management)
1.依赖范围
Maven在对项目进行编译,测试和运行时,会分别使用三套不同的classpath,Maven项目构建时,在不同阶段引入到classpath中的依赖可能不同。
我们可以在POM的依赖声明使用scope元素来控制依赖与三种classpath之间的关系,这就是依赖范围
常见的依赖范围
依赖范围 | 描述 |
---|---|
compile | 编译依赖范围,scope 元素的缺省值。使用此依赖范围的 Maven 依赖,对于三种 classpath 均有效,即该 Maven 依赖在上述三种 classpath 均会被引入。例如,log4j 在编译、测试、运行过程都是必须的。 |
test | 测试依赖范围。使用此依赖范围的 Maven 依赖,只对测试 classpath 有效。例如,Junit 依赖只有在测试阶段才需要。 |
provided | 已提供依赖范围。使用此依赖范围的 Maven 依赖,只对编译 classpath 和测试 classpath 有效。例如,servlet-api 依赖对于编译、测试阶段而言是需要的,但是运行阶段,由于外部容器已经提供,故不需要 Maven 重复引入该依赖。 |
runtime | 运行时依赖范围。使用此依赖范围的 Maven 依赖,只对测试 classpath、运行 classpath 有效。例如,JDBC 驱动实现依赖,其在编译时只需 JDK 提供的 JDBC 接口即可,只有测试、运行阶段才需要实现了 JDBC 接口的驱动。 |
system | 系统依赖范围,其效果与 provided 的依赖范围一致。其用于添加非 Maven 仓库的本地依赖,通过依赖元素 dependency 中的 systemPath 元素指定本地依赖的路径。鉴于使用其会导致项目的可移植性降低,一般不推荐使用。 |
import | 导入依赖范围,该依赖范围只能与 dependencyManagement 元素配合使用,其功能是将目标 pom.xml 文件中 dependencyManagement 的配置导入合并到当前 pom.xml 的 dependencyManagement 中。 |
依赖范围 | 编译 classpath | 测试 classpath | 运行 classpath | 例子 |
---|---|---|---|---|
compile | √ | √ | √ | log4j |
test | - | √ | - | junit |
provided | √ | √ | - | servlet-api |
runtime | - | √ | √ | JDBC-driver |
system | √ | √ | - | 非 Maven 仓库的本地依赖 |
依赖范围对传递依赖的影响
项目A依赖于项目B,B又依赖于项目C,此时我们可以将A对B的依赖称之为第一直接依赖,B对于C的依赖称之为第二直接依赖;间接依赖C会以传递性依赖的形式引入到A中,但这种引入会受到依赖范围的影响
一|二 | compile | test | provided | runtime |
---|---|---|---|---|
compile | compile | - | - | runtime |
test | test | - | - | test |
provided | provided | - | provided | provided |
runtime | runtime | - | - | runtime |
注:第一列是表示第一直接依赖的依赖范围,第一行表示第二直接依赖的依赖范围。交叉部分的取值为传递性依赖的依赖范围。
通过上表,总结出以下规律
- 第二直接依赖的范围为compile时,传递性依赖的范围与第一直接依赖的范围一致
- 第二直接依赖的范围为test时,传递性依赖不会被传递
- 第二直接依赖的范围为provided时,只传递第一直接依赖的范围也为provided的依赖,且传递性依赖的范围也为provided
- 第二直接依赖的范围为runtime时,传递性依赖的范围与第一直接依赖的范围一致,但compile例外,此时传递性依赖的范围为runtime
2.依赖调节
当一个间接依赖存在多条引入路径时,通过依赖调节来确定间接依赖的引入路径
- 引入路径短者优先
- 先声明者优先
(1).引入路径短者优先
例如A->B->C->D
和A->X->D
这两种情况会优先选择第二种情况
(2).先声明者优先
例如A->B->C
和A->X->D
这种不能通过路径短者优先来决定的,则看在POM文件中谁先声明,先声明者优先
3.排除依赖和可选依赖
根据依赖传递机制,项目在依赖过程中出于某种原因希望将某些间接依赖排除,Maven为用户提供了两种解决方式,排除依赖(Dependency Exclusions)和可选依赖(Optional Dependencies)
1.排除依赖
<dependencies>
<dependency>
<groupId>henrik</groupId>
<artifactId>henrik</artifactId