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>
<version>1.0-SNAPSHOT</version>
<exclusions>
<!-- 设置排除 -->
<!-- 排除依赖必须基于直接依赖中的间接依赖设置为可以依赖为 false -->
<!-- 设置当前依赖中是否使用间接依赖 -->
<exclusion>
<!--设置具体排除-->
<groupId>henrik</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
排除依赖是控制当前项目是否使用其直接依赖传递下来的间接依赖,通常出现在间接依赖间有功能冲突的地方
2.可选依赖
<dependencies>
<dependency>
<groupId>henrik</groupId>
<artifactId>henrik</artifactId>
<version>1.0-SNAPSHOT</version>
<!--设置可选依赖 -->
<optional>true</optional>
</dependency>
</dependencies>
可选依赖用来控制当前直接依赖是否向下传递,optional取true则表示不能向下传递
3.排除依赖和可选依赖结合
排除依赖通过控制间接依赖,可选依赖通过控制直接依赖;可选依赖优先级高于排除依赖
4.依赖管理(dependencyManagement)
依赖继承过程中,模块可能会引入一些不必要的依赖,这时可以通过dependencyManagement来管理依赖
-
父模块使用
dependencyManagement元素声明的依赖,父模块和子模块都不会引入该依赖 -
父模块中被
dependencyManagement元素声明的依赖,父模块和子模块通过dependecies进行引入,省略 version 和 scope则使用dependencyManagement元素中声明的版本 ,不省略version和scope则覆盖dependencyManagement元素中声明的版本
<!--dependencyManagement 标签用于控制子模块的依赖版本等信息 -->
<!-- 该标签只用来控制版本,不能将依赖引入 -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<!--引用的properties标签中定义的属性 -->
<version>1.2.17</version>
</dependency>
</dependencies>
</dependencyManagement>
<!--声明依赖-->
<dependencies>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
</dependency>
</dependencies>
使用依赖管理机制不能减少太多POM配置,但是仍然推荐这种方式的原因是:
- 父模块使用
dependencyManagement声明依赖能够统一项目内依赖的版本,降低了依赖冲突的几率 dependencyManagement声明的依赖不会被实际引入,子模块需要什么依赖就自己引入,增加了灵活性,避免引入一些不必要的依赖
继承,聚合
1.继承
当一个项目的多个模块都依赖于相同版本的相同依赖,且模块间没有依赖关系,就会导致同一依赖在多个模块中重复声明,我们可以通过POM继承的方式消除重复,即创建父模块,其它模块的POM可以通过继承父模块的POM来获得对相关依赖的声明
-
父模块POM的打包类型(packaging)必须是pom
-
子模块通过paren元素声明父模块
<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>henrik</groupId> <artifactId>henrik</artifactId> <version>1.0</version> <parent> <groupId>henrik</groupId> <artifactId>Root</artifactId> <version>1.0</version> <!-- <relativePath>../Root</relativePath> --> </parent> </project>元素 描述 是否必需 groupId 父模块的项目组 id。 是 artifactId 父模块 id。 是 version 父模块版本。 是 relativePath 父模块 POM 的相对路径,默认值为 …/pom.xml。 项目构建时,Maven 会先根据 relativePath 查找父模块 POM,如果找不到,再从本地仓库或远程仓库中查找。 否
子模块的POM中,当前groupId和version元素可以省略,子模块会隐式地从父模块中继承这两个元素,即由父模块控制子模块的公司组织id以及版本,这样可以简化POM的配置
可继承的POM元素
| 元素 | 描述 |
|---|---|
| groupId | 项目组 ID,项目坐标的核心元素 |
| version | 项目版本,项目坐标的核心元素 |
| description | 项目的描述信息 |
| organization | 项目的组织信息 |
| inceptionYear | 项目的创始年份 |
| url | 项目的URL地址 |
| developers | 项目的开发者信息 |
| contributors | 项目的贡献者信息 |
| distributionManagement | 项目的部署配置 |
| issueManagement | 项目的缺陷跟踪系统信息 |
| ciManagement | 项目的持续集成系统信息 |
| scm | 项目的版本控制系统信息 |
| mailingLists | 项目的邮件列表信息 |
| properties | 自定义的Maven属性 |
| dependencies | 项目的依赖配置 |
| dependencyManagement | 项目的依赖管理配置 |
| repositories | 项目的仓库配置 |
| build | 包括项目的源码目录配置、输出目录配置、插件配置、插件管理配置等 |
| reporting | 包括项目的报告输出目录配置、报告插件配置等 |
2.聚合
Maven聚合功能对项目进行构建时,需要在该项目中额外创建一个聚合模块,然后通过这个模块构建整个项目的所有模块;聚合模块仅仅是帮助聚合其他模块的工具,其本身并无任何实质内容,因此聚合模块中只有一个POM模块,不包含src/main/java,src/test/java等多个目录
聚合模块构建时,Maven会先解析聚合模块的POM,分析需要构建的模块,并根据这些模块之间的关系计算出构建顺序,然后根据该顺序依次构建各个模块
3.继承和聚合的关系
- 目的不同,继承为了消除POM中的重复配置,聚合为了方便地快速的构建项目
- 父模块不知道被哪些模块继承,子模块知道自己的父模块是谁
- 聚合模块知道哪些模块被聚合,被聚合模块不知道聚合模块的存在
- 两者打包方式都是pom,两者除了pom外都没有实际的代码内容
生命周期
maven出现之前,项目构建的生命周期就已经存在,但由于没有统一的规范,构建方式不尽相同
maven将项目的清理,初始化,编译,测试,打包,集成测试,验证,部署,站点生成等几乎所有构建过程进行了抽象和统一,总结出了高度完美的,易扩展的生命周期
maven的生命周期是抽象的,其本身不能做任何实际工作,这些实际工作都是通过调用maven插件中的插件目标(plugin goal)完成的。简单的理解就是:maven插件(子类)通过重写maven生命周期(抽象父类)的方法,通过插件目标(重写后的方法)的完成实际工作(如源代码编译)
Maven拥有三套标准的生命周期:
-
clean:用于清理项目
- pre-clean(清理前)
- clean(清理)
- post-clean(清理后)
-
default:用于构建项目
default生命周期定义了项目真正构建时所需的所有步骤,它是所有生命周期中最核心,最重要的部分,default生命周期包含非常多的阶段:
阶段 描述 validate 验证项目是否正确以及所有必要信息是否可用。 initialize 初始化构建状态。 generate-sources 生成编译阶段需要的所有源码文件。 process-sources 处理源码文件,例如过滤某些值。 generate-resources 生成项目打包阶段需要的资源文件。 process-resources 处理资源文件,并复制到输出目录,为打包阶段做准备。 compile 编译源代码,并移动到输出目录。 process-classes 处理编译生成的字节码文件 generate-test-sources 生成编译阶段需要的测试源代码。 process-test-sources 处理测试资源,并复制到测试输出目录。 test-compile 编译测试源代码并移动到测试输出目录中。 test 使用适当的单元测试框架(例如 JUnit)运行测试。 prepare-package 在真正打包之前,执行一些必要的操作。 package 获取编译后的代码,并按照可发布的格式进行打包,例如 JAR、WAR 或者 EAR 文件。 pre-integration-test 在集成测试执行之前,执行所需的操作,例如设置环境变量。 integration-test 处理和部署所需的包到集成测试能够运行的环境中。 post-integration-test 在集成测试被执行后执行必要的操作,例如清理环境。 verify 对集成测试的结果进行检查,以保证质量达标。 install 安装打包的项目到本地仓库,以供其他项目使用。 deploy 拷贝最终的包文件到远程仓库中,以共享给其他开发人员和项目。 -
site:用于建立项目站点
site生命周期的目的是建立和部署项目站点,Maven能够根据POM包含的信息,自动生成一个友好的站点,该站点包含一些与该项目有关的文档
- pre-site
- site
- post-site
- site-deploy
Maven可以通过插件
maven-site-plugin生成一个Web站点,以站点的形式发布项目描述 ,SCM地址,许可证信息,开发者信息等信息mvn site
插件
1.常用插件使用
maven实际上是一个依赖插件执行的框架,它执行的每个任务实际都由插件完成。Maven的核心发布包中不包括任何Maven插件,在maven需要使用某个插件时,才会去仓库下载
maven提供以下两种类型的插件
| 插件类型 | 描述 |
|---|---|
| Build plugins | 在项目构建过程中执行,在 pom.xml 中的 build 元素中配置 |
| Reporting plugins | 在网站生成过程中执行,在 pom.xml 中的 reporting 元素中配置 |
(1).插件目标
插件相当于一个类,插件目标相当于一个方法,
[插件名]:[插件目标名]:插件目标通用写法,如maven-compiler-plugin:compile
mvn [插件名]:[插件目标名]:maven命令执行插件的目标,如mvn compiler:compile
(2).插件绑定
为了完成具体的构建任务,Maven生命周期的阶段(抽象类的抽象方法)需要和Maven插件的目标(实现类的重写方法)相互绑定。例如,代码编译任务对应了default生命周期的compile阶段,而maven-compiler-plugin插件的compile目标能够完成这个任务,因此将它们绑定就能达到代码编译的目的
当插件目标绑定到生命周期的不同阶段时,其执行顺序由生命周期阶段的先后顺序决定,如果多个目标绑定到同一个生命周期阶段,其执行顺序与插件声明顺序一致,先设声明的先执行,后声明的后执行
内置绑定
maven默认为一些核心的生命周期阶段绑定了插件目标,当用户调用这些阶段时,对应的插件目标就会自动执行相应的任务
| 生命周期 | 阶段 | 插件目标 | 执行的任务 |
|---|---|---|---|
| clean | pre-clean | ||
| clean | maven-clean-plugin:clean | 清理 Maven 的输出目录 | |
| post-clean | |||
| site | pre-site | ||
| site | maven-site-plugin:site | 生成项目站点 | |
| post-site | |||
| site-deploy | maven-site-plugin:deploy | 部署项目站点 | |
| default | process-resources | maven-resources-plugin:resources | 复制资源文件到输出目录 |
| compile | maven-compiler-plugin:compile | 编译代码到输出目录 | |
| process-test-resources | maven-resources-plugin:testResources | 复制测试资源文件到测试输出目录 | |
| test-compile | maven-compiler-plugin:testCompile | 编译测试代码到测试输出目录 | |
| test | maven-surefire-plugin:test | 执行测试用例 | |
| package | maven-jar-plugin:jar/maven-jar-plugin:war | 创建项目 jar/war 包 | |
| install | maven-install-plugin:install | 将项目输出的包文件安装到本地仓库 | |
| deploy | maven-deploy-plugin:deploy | 将项目输出的包文件部署到到远程仓库 |
自定义绑定
<!-- 添加插件 maven-antrun-plugin-->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<executions>
<!-- 将该插件的run目标绑定到clean生命周期中的pre-clean,clean和post-clean三个阶段中,
以实现在clean生命周期的各个阶段显示自定义文本信息 -->
<execution>
<!-- 自定义阶段id -->
<id>henrik pre-clean</id>
<!-- 阶段 -->
<phase>pre-clean</phase>
<!-- 目标 -->
<goals>
<goal>run</goal>
</goals>
<!-- 配置 -->
<configuration>
<!-- 执行的任务 -->
<tasks>
<!-- 输出自定义文本信息 -->
<echo>henrik:pre-clean预清理阶段</echo>
</tasks>
</configuration>
</execution>
<execution>
<!-- 自定义阶段id -->
<id>henrik clean</id>
<!-- 阶段 -->
<phase>clean</phase>
<!-- 目标 -->
<goals>
<goal>run</goal>
</goals>
<!-- 配置 -->
<configuration>
<!-- 执行的任务 -->
<tasks>
<!-- 输出自定义文本信息 -->
<echo>henrik:clean清理阶段</echo>
</tasks>
</configuration>
</execution>
<execution>
<!-- 自定义阶段id -->
<id>henrik post-clean</id>
<!-- 阶段 -->
<phase>post-clean</phase>
<!-- 目标 -->
<goals>
<goal>run</goal>
</goals>
<!-- 配置 -->
<configuration>
<!-- 执行的任务 -->
<tasks>
<!-- 输出自定义文本信息 -->
<echo>henrik:post-clean后清理阶段</echo>
</tasks>
</configuration>
</execution>
<!-- 将该插件的run目标绑定到default生命周期中的部分阶段中,
以实现在clean生命周期的特定阶段显示自定义文本信息 -->
<execution>
<!-- 自定义阶段id -->
<id>henrik test</id>
<!-- 阶段 -->
<phase>test</phase>
<!-- 目标 -->
<goals>
<goal>run</goal>
</goals>
<!-- 配置 -->
<configuration>
<!-- 执行的任务 -->
<tasks>
<!-- 输出自定义文本信息 -->
<echo>henrik:default-test测试阶段</echo>
</tasks>
</configuration>
</execution>
<execution>
<!-- 自定义阶段id -->
<id>henrik package</id>
<!-- 阶段 -->
<phase>package</phase>
<!-- 目标 -->
<goals>
<goal>run</goal>
</goals>
<!-- 配置 -->
<configuration>
<!-- 执行的任务 -->
<tasks>
<!-- 输出自定义文本信息 -->
<echo>henrik:default-package打包阶段</echo>
</tasks>
</configuration>
</execution>
<execution>
<!-- 自定义阶段id -->
<id>henrik deploy</id>
<!-- 阶段 -->
<phase>deploy</phase>
<!-- 目标 -->
<goals>
<goal>run</goal>
</goals>
<!-- 配置 -->
<configuration>
<!-- 执行的任务 -->
<tasks>
<!-- 输出自定义文本信息 -->
<echo>henrik:default-deploy部署阶段</echo>
</tasks>
</configuration>
</execution>
<!-- 将该插件的run目标绑定到site生命周期中的所有阶段中,
以实现在site生命周期的所有阶段显示自定义文本信息 -->
<execution>
<!-- 自定义阶段id -->
<id>henrik pre-site</id>
<!-- 阶段 -->
<phase>pre-site</phase>
<!-- 目标 -->
<goals>
<goal>run</goal>
</goals>
<!-- 配置 -->
<configuration>
<!-- 执行的任务 -->
<tasks>
<!-- 输出自定义文本信息 -->
<echo>henrik:pre-site阶段</echo>
</tasks>
</configuration>
</execution>
<execution>
<!-- 自定义阶段id -->
<id>henrik site</id>
<!-- 阶段 -->
<phase>site</phase>
<!-- 目标 -->
<goals>
<goal>run</goal>
</goals>
<!-- 配置 -->
<configuration>
<!-- 执行的任务 -->
<tasks>
<!-- 输出自定义文本信息 -->
<echo>henrik:site编译阶段</echo>
</tasks>
</configuration>
</execution>
<execution>
<!-- 自定义阶段id -->
<id>henrik post-site</id>
<!-- 阶段 -->
<phase>post-site</phase>
<!-- 目标 -->
<goals>
<goal>run</goal>
</goals>
<!-- 配置 -->
<configuration>
<!-- 执行的任务 -->
<tasks>
<!-- 输出自定义文本信息 -->
<echo>henrik:post-site阶段</echo>
</tasks>
</configuration>
</execution>
<execution>
<!-- 自定义阶段id -->
<id>henrik site-deploy</id>
<!-- 阶段 -->
<phase>site-deploy</phase>
<!-- 目标 -->
<goals>
<goal>run</goal>
</goals>
<!-- 配置 -->
<configuration>
<!-- 执行的任务 -->
<tasks>
<!-- 输出自定义文本信息 -->
<echo>henrik:site-deploy阶段</echo>
</tasks>
</configuration>
</execution>
</executions>
</plugin>
关于executions
executions元素定义了一些执行配置,每个execution子元素都可以用来配置执行一个任务。
- id:任务的唯一标识
- phase:插件目标需要绑定的生命周期阶段
- goals:用于指定一组插件目标,其子元素goal用于指定一个插件目标
- configuration:该任务的配置,其子元素tasks用于指定该插件目标执行的任务
2.插件管理(pluginManagement)
与dependencyManagement依赖管理使用方式类似
Archetype(原型/模板),SNAPSHOT(快照)
1.原型
Archetype是maven项目的模板工具包,它定义了Maven的基本架构,Maven通过Archetype可以帮助用户快速地生成项目的目录结构以及POM文件
- maven-archetype-plugin:Archetype插件
- archetype-packaging:用于描述Archetype的生命周期与构建项目软件包
- archetype-models:用于描述类与引用
- archetype-common:核心类
- archetype-testing:用于测试Maven Archetype的内部组件
2.快照
当被依赖的项目模块需要在开发过程中高频率地更新代码以及发布版本,这是就可以使用SNAPSHOT(快照)版本让依赖该构件的项目使用
SNAPSHOT(快照)是一种特殊的版本,它表示当前开发进度的副本,与常规版本不同,快照版本的构件在发布时(通过在pom.xml中版本号后加上-SNAPSHOT),Maven会自动为它打上时间戳,依赖该构件的项目进行构建时,Maven就能从仓库中找到最新的SNAPSHOT版本文件,通过以下命令可以强制Maven检查构件快照的更新
mvn clean package -U
SNAPSHOT版本,RELEASE版本
| 区别 | SNAPSHOT 版本 | RELEASE 版本 |
|---|---|---|
| 定义 | 版本号中带有 -SNAPSHOT | 版本号中不带有 -SNAPSHOT |
| 发布仓库 | Snapshot 快照仓库 | Release 发行仓库 |
| 是否从远程仓库自动获取更新 | 在不更改版本号的前提下,直接编译打包时,Maven 会自动从远程仓库上下载最新的快照版本。 | 在不更改版本号的前提下,直接编译打包时,如果本地仓库已经存在该版本的模块,则 Maven 不会主动去远程仓库下载。 |
| 稳定性 | 快照版本往往对应了大量带有时间戳的构件,具有不稳定性。 | 发布版本只对应了唯一的构件,具有稳定性。 |
| 使用场景 | 快照版本只应该在组织内部的项目中依赖使用。 | Maven 项目使用的组织外的依赖项都应该时发布版本的,不应该使用任何的快照版本依赖,否则会造成潜在的风险。 |
| 发布前是否需要修改 | 当项目经过完善的测试后,需要上线时,应该将项目从快照版本更改为发布版本 | 不需要修改 |
Maven Profile
maven引入Profile的概念,它可以为不同环境定制不同的构建构建过程
Q&A:什么是Profile?
profile=properties+file,可直译为配置文件,在程序开发过程中通常用于在不同环境(开发,测试,生产等)运用不不同的配置信息
自动化构建
自动化构建指当某个项目构建完成后,所有依赖它的相关项目也应该开始构建过程,以确保这些项目的稳定运行
- 使用
maven-invoker-plugin插件 - 使用持续集成(CI)服务器自动管理构建自动化,例如Jekins
<plugins>
<!-- 添加invoker 插件 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-invoker-plugin</artifactId>
<version>3.2.2</version>
<configuration>
<debug>true</debug>
<!--设置 invkoer插件 添加的 pom 文件所在的文件夹 -->
<projectsDirectory>D:\maven</projectsDirectory>
<!-- 设置 invkoer插件 添加的 pom 文件 -->
<pomIncludes>
<pomInclude></pomInclude>
<pomInclude></pomInclude>
</pomIncludes>
</configuration>
<executions>
<execution>
<id>henrik-invoker</id>
<!-- 执行的目标 -->
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
- projectsDirectory:需要构建项目的目录,该元素可单独使用,表示该目录下的所有Maven项目都会在当前项目构建完成后开始构建
- pomIncludes:该元素内可以声明一个或多个pomInclude元素,需与projectDirectory元素配合使用,共同指定需要构建项目的pom.xml
通过以下命令查看maven-invoker-plugin插件绑定的目标
mvn help:describe -Dplugin=invoker
Maven是一款基于Java的项目管理和整合工具,遵循约定优于配置原则,具有标准的目录结构和默认构建生命周期。它通过POM(项目对象模型)管理项目依赖、构建任务和插件,提供自动化构建功能。Maven的生命周期包括clean、default和site三个阶段,插件通过绑定生命周期阶段完成具体任务。此外,Maven支持Archetype用于项目模板创建,以及SNAPSHOT版本管理,便于开发过程中的频繁更新。
1万+

被折叠的 条评论
为什么被折叠?



