一、什么是Maven
Maven 是一个流行的 Java 项目构建和管理工具,它包含了一个项目对象模型 (POM Project Object Model) 一组标准集合。不仅简化了我们开发过程中对jar包依赖的导入,还对项目的清理、初始化、编译、测试、打包、集成测试、验证、部署和站点生成等所有构建过程进行了抽象和统一。由于 Maven 使用标准目录布局和默认构建生命周期,开发团队几乎可以立即自动化项目的构建基础设施。在多个开发团队环境的情况下Maven 可以在很短的时间内按照标准设置工作方式。
Maven 之前更多的是使用 Ant 进行项目构建,Ant 有一个特点每次都得写每次都写的差不多配置也臃肿。不过目前在Java 领域 Maven 使用比较多,除了 Maven还有 Gradle。
二、Maven能够解决什么问题
-
自动化构建:Maven 可以自动执行编译、测试、打包等操作,从而简化了项目构建的过程。
-
依赖管理:Maven 可以帮助我们自动下载和管理项目所需的依赖,避免了手动下载和管理依赖的繁琐过程。
-
插件支持:Maven 提供了丰富的插件,可以帮助我们完成各种任务,如代码分析、测试覆盖率检查、部署等。
-
标准化项目结构:Maven 规定了标准的项目结构,使得开发者能够更容易地理解和维护项目。
-
构建生命周期管理:Maven 定义了一套完整的构建生命周期,使得开发者能够更好地控制构建过程。
-
多模块项目管理:Maven 支持多模块项目,可以将一个大型项目拆分成多个子模块,并统一管理依赖、插件等。
三、Maven有什么功能
Maven是一个Java项目管理和自动化构建工具,支持以下功能:
-
依赖管理:Maven可以通过POM文件来管理项目所需的依赖关系,根据依赖关系下载并自动安装所需库或插件。
-
自动化构建:Maven支持自动化构建过程,包括编译、测试、打包、发布等一系列任务,并且可以自定义构建规则和流程。
-
多模块支持:可以将一个大型项目划分为多个小模块,每个模块都有自己的POM文件和版本号,方便各个模块之间的依赖管理和独立构建。
-
插件机制:Maven提供了很多可扩展的插件,可以满足不同项目的需要。也可以使用自己编写的插件来实现特定的功能。
-
统一的项目结构:Maven规范化了项目的结构,使得不同项目具有相似的目录结构和命名规则,使得开发者能够快速理解和维护项目。
-
可重复性构建:Maven保证了构建过程的可重复性,即在不同的环境下构建结果应该相同,这对于团队协作和持续集成非常重要。
总之,Maven提供了一种标准的、可扩展的和易于使用的方式来管理Java项目,可以大大简化项目构建和依赖管理的复杂度。
四、Maven模型
Maven模型是指Maven构建工具中的一种规范化的项目结构和依赖管理方式。它包括POM文件(Project Object Model),定义了项目的元数据,如名称、描述、版本等信息,以及项目的依赖关系和构建配置等。 Maven使用这个模型来管理构建过程中需要的库和插件,并且可以自动解决依赖关系,简化了项目构建和管理的复杂度。
1、Maven项目对象模型(POM)是Maven中用于描述项目的元数据和构建配置的XML文件。POM文件包含了项目的基本信息,例如名称、版本、开发者、许可证等,同时还定义了项目的依赖关系、构建配置和插件等。 Maven使用POM文件来管理项目的构建过程,通过解析POM文件中的依赖关系,自动下载所需依赖项,并使用预定义的构建规则来生成目标文件。 POM文件通常存储在项目根目录下的pom.xml文件中。
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.6.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.biyu</groupId>
<artifactId>study-demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>study-demo</name>
<description>study-demo</description>
<properties>
<java.version>11</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.derby</groupId>
<artifactId>derby</artifactId>
<version>10.14.2.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.6.5</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
2、Maven项目标识符是指在Maven中唯一标识一个项目的三元组:groupId、artifactId和version。
- groupId是组织或公司的唯一标识符,通常使用反转的域名表示。例如,org.apache.maven。
- artifactId是当前项目的唯一标识符,通常使用短横线分隔的小写字母来表示。例如,maven-core。
- version是当前项目的版本号,通常使用X.Y.Z这样的格式来表示。例如,1.0.0。
通过这三个元素,Maven可以准确定位并下载需要的依赖关系,也可以发布和管理自己的库和插件。例如,如果两个不同的项目具有相同的groupId和artifactId,但是不同的版本号,则它们代表两个不同的项目,并且可以共存于同一Maven仓库中。
节点 | 描述 |
---|---|
project | 工程的根标签。 |
modelVersion | 模型版本需要设置为 4.0。 |
groupId | 这是工程组的标识。它在一个组织或者项目中通常是唯一的。例如,一个银行组织 com.companyname.project-group 拥有所有的和银行相关的项目。 |
artifactId | 这是工程的标识。它通常是工程的名称。例如,消费者银行。groupId 和 artifactId 一起定义了 artifact 在仓库中的位置。 |
version | 这是工程的版本号。在 artifact 的仓库中,它用来区分不同的版本。例如: com.biyu.demo:study-demo:1.0 com.biyu.demo:study-demo:1.1 |
3、Maven 的依赖管理是它最重要的特性之一,它可以自动管理项目所需的依赖项,包括下载、版本控制和传递依赖。
如上图,项目 A 依赖于项目 B,B 又依赖于项目 C,此时 B 是A的直接依赖,C 是A的间接依赖
Maven 的依赖传递机制是指不管 Maven 项目存在多少间接依赖,POM 中都只需要定义其直接依赖,不必定义任何间接依赖,Maven 会动读取当前项目各个直接依赖的 POM,将那些必要的间接依赖以传递性依赖的形式引入到当前项目中。Maven 的依赖传递机制能够帮助用户一定程度上简化 POM 的配置。
Maven 可以避免去搜索所有所需库的需求。Maven 通过读取项目文件(pom.xml),找出它们项目之间的依赖关系。
我们需要做的只是在每个项目的 pom 中定义好直接的依赖关系。其他的事情 Maven 会帮我们搞定。
通过可传递性的依赖,所有被包含的库的图形会快速的增长。当有重复库时,可能出现的情形将会持续上升。Maven 提供一些功能来控制可传递的依赖的程度。
功能 | 功能描述 |
---|---|
依赖调节 | 决定当多个手动创建的版本同时出现时,哪个依赖版本将会被使用。 如果两个依赖版本在依赖树里的深度是一样的时候,第一个被声明的依赖将会被使用。 |
依赖管理 | 直接的指定手动创建的某个版本被使用。例如当一个工程 C 在自己的依赖管理模块包含工程 B,即 B 依赖于 A, 那么 A 即可指定在 B 被引用时所使用的版本。 |
依赖范围 | 包含在构建过程每个阶段的依赖。 |
依赖排除 | 任何可传递的依赖都可以通过 "exclusion" 元素被排除在外。举例说明,A 依赖 B, B 依赖 C,因此 A 可以标记 C 为 "被排除的"。 |
依赖可选 | 任何可传递的依赖可以被标记为可选的,通过使用 "optional" 元素。例如:A 依赖 B, B 依赖 C。因此,B 可以标记 C 为可选的, 这样 A 就可以不再使用 C。 |
4、依赖范围
传递依赖发现可以通过使用如下的依赖范围来得到限制:
范围 | 描述 |
---|---|
编译阶段 | 该范围表明相关依赖是只在项目的类路径下有效。默认取值。 |
供应阶段 | 该范围表明相关依赖是由运行时的 JDK 或者 网络服务器提供的。 |
运行阶段 | 该范围表明相关依赖在编译阶段不是必须的,但是在执行阶段是必须的。 |
测试阶段 | 该范围表明相关依赖只在测试编译阶段和执行阶段。 |
系统阶段 | 该范围表明你需要提供一个系统路径。 |
导入阶段 | 该范围只在依赖是一个 pom 里定义的依赖时使用。同时,当前项目的POM 文件的 部分定义的依赖关系可以取代某特定的 POM。 |
Maven 通过在 pom.xml
文件中添加 <dependencies>
标签来管理项目的依赖项。例如:
<dependencies>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.12.0</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
</dependencies>
上面的例子中,我们定义了两个依赖项:org.apache.commons:commons-lang3:3.12.0
和 junit:junit:4.13.2
,其中第二个依赖项的作用域为 test
,表示该依赖项仅在测试代码中使用。
当我们运行 Maven 构建时,Maven 会自动下载这些依赖,并将它们添加到项目的类路径中。此外,Maven 还支持传递依赖,即如果一个依赖项依赖于其他依赖项,那么 Maven 会自动下载并添加这些依赖项。
除了标准的 Maven 仓库外,Maven 还支持自定义仓库地址和本地仓库。我们可以通过在 settings.xml
文件中添加 <repositories>
和 <localRepository>
标签来配置自定义仓库和本地仓库。
总之,Maven 的依赖管理功能是它最强大的特性之一,可以帮助开发者自动下载、管理和传递项目所需的依赖项,从而提高项目的可维护性和开发效率。
五、Maven 仓库
Maven 仓库是用于存储 Maven 项目构建所需的依赖项和插件的中央存储库。它可以是本地机器上的本地仓库,也可以是网络上的远程仓库。Maven 会自动搜索这些仓库以查找所需的依赖项和插件,并将其下载到本地仓库供构建使用。
Maven 依赖加载顺序
当我们执行 Maven 构建命令时Maven 开始按以下顺序查找依赖库
1、在本地存储库中搜索依赖项如果未找到则转到2,否则执行进一步处理。
2、如果没有提到远程存储库则跳转到3 。在一个或多个远程存储库中搜索依赖项如果找到则将其下载到本地存储库以供将来参考
3、在中央存储库中搜索依赖项将其下载到本地存储库以供将来参考。如果未找到 Maven 只是停止处理并抛出错误无法找到依赖项
六、Maven 构建生命周期
Maven 构建生命周期定义了一个项目构建跟发布的过程。
一个典型的 Maven 构建(build)生命周期是由以下几个阶段的序列组成的:
阶段 | 处理 | 描述 |
---|---|---|
验证 validate | 验证项目 | 验证项目是否正确且所有必须信息是可用的 |
编译 compile | 执行编译 | 源代码编译在此阶段完成 |
测试 Test | 测试 | 使用适当的单元测试框架(例如JUnit)运行测试。 |
包装 package | 打包 | 创建JAR/WAR包如在 pom.xml 中定义提及的包 |
检查 verify | 检查 | 对集成测试的结果进行检查,以保证质量达标 |
安装 install | 安装 | 安装打包的项目到本地仓库,以供其他项目使用 |
部署 deploy | 部署 | 拷贝最终的工程包到远程仓库中,以共享给其他开发人员和工程 |
为了完成 default 生命周期,这些阶段(包括其他未在上面罗列的生命周期阶段)将被按顺序地执行。
Maven 有以下三个标准的生命周期:
1、Clean 生命周期
当我们执行 mvn post-clean 命令时,Maven 调用 clean 生命周期,它包含以下阶段:
- pre-clean:执行一些需要在clean之前完成的工作
- clean:移除所有上一次构建生成的文件
- post-clean:执行一些需要在clean之后立刻完成的工作
mvn clean 中的 clean 就是上面的 clean,在一个生命周期中,运行某个阶段的时候,它之前的所有阶段都会被运行,也就是说,如果执行 mvn clean 将运行以下两个生命周期阶段:
pre-clean, clean
如果我们运行 mvn post-clean ,则运行以下三个生命周期阶段:
pre-clean, clean, post-clean
2、Default (Build) 生命周期
这是 Maven 的主要生命周期,被用于构建应用,包括下面的 23 个阶段:
生命周期阶段 | 描述 |
---|---|
validate(校验) | 校验项目是否正确并且所有必要的信息可以完成项目的构建过程。 |
initialize(初始化) | 初始化构建状态,比如设置属性值。 |
generate-sources(生成源代码) | 生成包含在编译阶段中的任何源代码。 |
process-sources(处理源代码) | 处理源代码,比如说,过滤任意值。 |
generate-resources(生成资源文件) | 生成将会包含在项目包中的资源文件。 |
process-resources (处理资源文件) | 复制和处理资源到目标目录,为打包阶段最好准备。 |
compile(编译) | 编译项目的源代码。 |
process-classes(处理类文件) | 处理编译生成的文件,比如说对Java class文件做字节码改善优化。 |
generate-test-sources(生成测试源代码) | 生成包含在编译阶段中的任何测试源代码。 |
process-test-sources(处理测试源代码) | 处理测试源代码,比如说,过滤任意值。 |
generate-test-resources(生成测试资源文件) | 为测试创建资源文件。 |
process-test-resources(处理测试资源文件) | 复制和处理测试资源到目标目录。 |
test-compile(编译测试源码) | 编译测试源代码到测试目标目录. |
process-test-classes(处理测试类文件) | 处理测试源码编译生成的文件。 |
test(测试) | 使用合适的单元测试框架运行测试(Juint是其中之一)。 |
prepare-package(准备打包) | 在实际打包之前,执行任何的必要的操作为打包做准备。 |
package(打包) | 将编译后的代码打包成可分发格式的文件,比如JAR、WAR或者EAR文件。 |
pre-integration-test(集成测试前) | 在执行集成测试前进行必要的动作。比如说,搭建需要的环境。 |
integration-test(集成测试) | 处理和部署项目到可以运行集成测试环境中。 |
post-integration-test(集成测试后) | 在执行集成测试完成后进行必要的动作。比如说,清理集成测试环境。 |
verify (验证) | 运行任意的检查来验证项目包有效且达到质量标准。 |
install(安装) | 安装项目包到本地仓库,这样项目包可以用作其他本地项目的依赖。 |
deploy(部署) | 将最终的项目包复制到远程仓库中与其他开发者和项目共享。 |
有一些与 Maven 生命周期相关的重要概念需要说明:
当一个阶段通过 Maven 命令调用时,例如 mvn compile,只有该阶段之前以及包括该阶段在内的所有阶段会被执行。
不同的 maven 目标将根据打包的类型(JAR / WAR / EAR),被绑定到不同的 Maven 生命周期阶段。
3、Site 生命周期
Maven Site 插件一般用来创建新的报告文档、部署站点等。
- pre-site:执行一些需要在生成站点文档之前完成的工作
- site:生成项目的站点文档
- post-site: 执行一些需要在生成站点文档之后完成的工作,并且为部署做准备
- site-deploy:将生成的站点文档部署到特定的服务器上
这里经常用到的是site阶段和site-deploy阶段,用以生成和发布Maven站点,这可是Maven相当强大的功能,Manager比较喜欢,文档及统计数据自动生成,很好看。 在下面的例子中,我们将 maven-antrun-plugin:run 目标添加到 Site 生命周期的所有阶段中。这样我们可以显示生命周期的所有文本信息。
Maven 规定了插件在特定的生命周期阶段执行,也可以通过配置 pom.xml 文件来自定义构建流程。
七、插件Plugin
插件管理与依赖管理原理一样、不同的是定义的元素标签不一样、插件管理标签是build标签的子标签pluginManagement
中。
pluginManagement
用来做插件管理的。它是表示插件声明即你在项目中的pluginManagement
下声明了插件Maven不会加载该插件pluginManagement
声明可以被继承。如下面的例子
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>2.1</version>
<configuration>
<attach>true</attach>
</configuration>
<executions>
<execution>
<phase>compile</phase>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</pluginManagement>
<!-- 子POM-->
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
</plugin>
</plugins>