Maven笔记整理

Maven

环境配置

  1. Maven 是一个基于 Java 的工具,所以要做的第一件事情就是安装 JDK
  2. Maven 自身安装需要大约 10 MB 空间。除此之外,额外的磁盘空间将用于你的本地 Maven 仓库。你本地仓库的大小取决于使用情况

坐标

  • groupId:当前Maven项目隶属项目。
    • Maven项目和实际项目不一定是一对一的关系(模块的原因)
    • 不应该对应项目隶属的组织或公司(一个组织下会有多个实际项目)
    • 表示方式与java包名方式类似,通常与域名反向一一对应
  • artifactId:定义项目中实际的一个Maven项目(模块)
    • 推荐使用项目实际项目名称作为artifactId的前缀
  • version:Maven项目当前所处版本
  • packaging:打包方式
    • 打包方式通常与生成构建的文件拓展名对应
    • 打包方式会影响到构建的生命周期
    • 默认打包方式为jar
  • classifier:定义输出的一些附属组件
    • 附属组件与主构件对应,例如Java文档和源代码

groupId、artifactId、version必须定义,packaging可选,classifier不能直接定义

项目构建的文件名始于坐标相对应的,一般规则为artifactId-version[-classifier].packaging

依赖

  • groupId、artifactId、version:依赖的基本坐标
  • type:依赖类型,默认为jar
  • scope:依赖范围
  • optional:依赖是否可选
  • exclusions:排除传递性依赖

依赖范围

Maven在编译、测试、运行(含打包)阶段中所需的依赖并不完全一致,依赖范围就是用来控制依赖与三种classpath(编译classpath、测试classpath、运行classpath)的关系。

范围 classpath范围 例子 补充
编译
compile
编译、测试、运行 spring-core 默认依赖范围
供应
provided
编译、测试 servlet-api 如果不显示指定该依赖范围,并且容器依赖的版本和maven依赖的版本不一致的话,可能会引起版本冲突,造成不良影响。
运行
runtime
测试、运行 JDBC驱动
测试
test
测试 Junit 编译主代码和运行项目时使无法使用此依赖
系统
system
编译、测试 必须通过配置systemPath元素来显示指定依赖文件的路径,此类依赖不是由maven仓库解析的,而且往往与本机系统绑定,可能造成构件的不可移植,因此谨慎使用。systemPath可以引用环境变量
导入
import
不会对三种classpath产生影响,该依赖范围只能与dependencyManagement元素配合使用
将目标pom文件中dependencyManagement的配置导入合并到当前pom的dependencyManagement中。

可传递性依赖

Maven会解析各个直接依赖的POM,将那些必要的间接依赖,以传递性依赖的形式引入到当前的项目中

可传递性依赖和依赖范围

第一直接依赖 \ 第二直接依赖 compile test provided runtime
compile compile runtime
test test test
provided provided provided provided
runtime runtime runtime

依赖调节

  • 路径最近者优先
  • 第一声明者优先

可能导致问题:依赖冲突。依赖的版本和实际使用的版本不一致,常见的表现有NoSuchMethodError,ClassNotFoundException 等。

解决方法:依赖排除

可选依赖

元素为true,标识当前依赖为可选依赖,该依赖不会得到传递

理想情况下,是不应该使用可选依赖的,用可选依赖的某一个原因是某一个项目实现了多个特性,这违反了单一职责性原则

排除依赖

元素声明排除依赖,可以包含一个或多个元素,因此可以排除一个或多个传递性依赖。

**声明的时候只需要groupId和artifactId,而不需要version元素。**因为只需要groupId和artifactId就能唯一定位依赖图中的某个依赖,即Maven解析后的依赖中,不可能出现groupId和artifactId相同,而version不同的两个依赖。

归类依赖

原因:同一项目下不同依赖的版本相同,避免重复

  • 使用properties元素定义Maven属性
  • 使用Maven属性(${属性名})代替实际version值

优化依赖

  • 已解析依赖(Resolved Dependency):Maven会自动解析所有项目的直接依赖和传递性依赖,并且根据规则正确判断每个依赖的范围,对于一些依赖冲突,也能进行调节,以确保任何一个构建只有唯一的版本在依赖中存在。最后得到的依赖称为已解析依赖。

查看命令:

mvn dependency:list
  • 依赖树:将当前项目POM声明的依赖定义为顶层依赖,而这些依顶层依赖的依赖规则定义为第二层依赖,以此类推,有第三、第四层依赖。

查看命令:

mvn dependency:tree
  • 解析依赖

查看命令:

mvn dependency:analyze

Used undeclared dependencies:项目中使用到,但没有显示声明的依赖。存在这潜在的危险,当直接依赖升级时,相关传递依赖的版本也可能发生变化,这种变化不易察觉,但是有可能导致当前项目出错

Unused declared dependencies:项目中未使用到,到显示声明的依赖。不能简单的直接删除,需要仔细分析,因为dependency:analyze只会分析编译主代码和测试代码需要用到的依赖,一些执行测试和运行时需要的依赖它就发现不了

排除依赖 VS 可选依赖

排除依赖和可选依赖都能在项目中将间接依赖排除在外,但两者实现机制却完全不一样。

  • 排除依赖是控制当前项目是否使用其直接依赖传递下来的接间依赖;
  • 可选依赖是控制当前项目的依赖是否向下传递;
  • 可选依赖的优先级高于排除依赖
  • 若对于同一个间接依赖同时使用排除依赖和可选依赖进行设置,那么可选依赖的取值必须为 false,否则排除依赖无法生效。

仓库

任何一个依赖、插件或者项目构建的输出,都可以称为构建。坐标和依赖时任何一个构件在Maven世界中的逻辑表示方式,而构件的物理表示方式是文件。

Maven仓库是统一存储所有Maven项目共享的构件的位置。实际的Maven项目将不再各自存储其依赖文件,只需要声明这些依赖的坐标,在需要的时候,Maven会自动根据坐标找到仓库中的构件并使用

布局

仓库路径与坐标的大致对应关系为:groupId/artifactId/version/artifactId-version.packaging

分类

仓库只有两类:本地仓库和远程仓库。

Maven寻找构件过程:

  • 查看本地仓库,若存在,直接使用
  • 本地仓库不存在或需要查看是否有更新,Maven就需要去远程仓库查找,找到需要的构件后下载到本地再使用
  • 若本地和远程仓库都找不到,则会报错

特殊的远程仓库:

  • 中央仓库:Maven核心自带的远程仓库,包含了绝大部分开源的构件,在默认的配置下,当本地仓库没有需要的构件时会尝试从中央仓库下载
  • 私服:为了节省宽带和时间,在局域网内假设的一个私有的仓库服务器,用其代理所有外部的远程仓库
  • 其他公开的远程仓库

本地仓库

目录地址:settings.xml中标签设置,默认为~/.m2/repository/

构件下载到本地仓库的方式:①从Maven远程仓库下载,②mvn install将本地项目安装到仓库中

安装Maven后,如果不执行任何Maven命令,本地仓库目录时不存在的。当执行第一条Maven命令后,Maven才会创建本地仓库

远程仓库

每个用户只有一个本地仓库,但是可以配置访问多个远程仓库

中央仓库

由于原始本地仓库是空的,Maven必须知道至少一个可用的远程仓库,才能在执行Maven命令的时候下载到需要的构件

中央仓库就是一个默认的远程仓库,Maven安装文件自带了中央仓库的配置(pom-4.0.0.xml)

私服

一些无法从外部仓库下载到的构件也能从本地上传到私服上供局域网内的Maven用户使用

优势:

  • 节省外网宽带
  • 加速Maven构建:Maven的一些内部机制(比如快照更新检查)要求Maven在执行构建的时候不停的检查远程仓库数据
  • 部署第三方构件
  • 提高稳定性,增强控制
  • 降低中央仓库的负载

远程仓库

配置

pom.xml中元素下,子元素声明一个或多个远程仓库。

元素对仓库进行唯一的标识,Maven自带的中央仓库使用的id是central,如果其他的仓库声明也使用了该id,就会覆盖中央仓库的配置

元素指向了仓库的地址,一般来说,这个地址是基于http协议,可以直接在浏览器在打开地址浏览构件

和元素用来控制Maven对于发布版构件和快照版构件的下载。子元素为true表示会下载,false表示不会下载。

元素default表示仓库的布局是Maven2和Maven3的默认布局,而不是Maven1的布局

元素,用来配置从远程仓库检查更新的频率:

  • daily:默认值,每天检查一次
  • never:从不检查更新
  • always:每次构件都检查更新
  • interval:X–每个X分钟检查更新一次,X为任意整数

元素,配置检查 校验和 文件的策略:

  • warn:默认值,在执行构件时输出警告信息
  • fail:遇到 校验和 错误就让构建失败
  • ignore:完全忽略 校验和 错误

认证

settings.xml中配置,因为pom.xml会提交到代码仓库中,而settings.xml一般只会放在本地,比较安全

下子元素配置认证信息,**关键是元素,需要与POM中需要认证的repositore元素的id完全一致。**正是这个id将认证信息与仓库配置联系在了一起

部署

POM中元素下和子元素,前者表示发布版构件的仓库,后者表示快照版的仓库。两个元素都需要配置id、name和url,id为该远程仓库的唯一标识,name是方便阅读,url是仓库地址

命令:

mvn clean deploy

快照

Maven世界中,任何一个项目或构件都必须有自己的版本。

快照版本发布到私服的过程中,Maven会自动为构件打上时间戳,有了时间戳,Maven就能随时找到快照版构件的最新版本。

默认情况下,Maven每天检查一次快照版更新,可使用-U参数强制更新

快照版值应该在组织内部的项目或模块间依赖使用

仓库依赖解析机制

  1. 依赖范围是system,Maven直接从本地文件系统解析构件
  2. 根据依赖坐标计算仓库路径后,尝试直接从本地仓库寻找构件
  3. 本地仓库找不到情况下,如果依赖版本是显示的发布版本构件,则遍历所有远程仓库,下载并解析使用
  4. 如果依赖版本是RELEASE或LATEST,则基于更新策略读取远程仓库的元数据groupId/artifactId/maven-metadata.xml,与本地元数据合并后,计算真实值,然后基于这个值检查本地仓库和远程仓库(步骤2、3)
  5. 如果版本是SNAPSHOT,则基于更新策略读取所有远程仓库的元数据roupId/artifactId/maven-metadata.xml,与本地元数据合并后,计算真实值,然后基于该值检查本地仓库和远程仓库
  6. 如果最后解析得到的构件版本是时间戳格式的快照,则复制其时间戳格式的文件至非时间戳格式。

RELEASE和LATEST分别对应仓库中该构件的最新发布版本和最新版本(含快照),不推荐使用这两种做法

Maven3不再支持在插件配置中使用RELEASE和LATEST,如果不设置插件版本,其效果和RELEASE一样。

maven-metadata.xml的元素包含两个子元素,分别代表了这一快照的时间戳和构建号,基于这两个元素可以得到该仓库中此快照的最新构建版本号。仓库元数据并不是永远正确的

镜像

settings.xml中元素下配置镜像。

值为被镜像的仓库id,如果镜像需要认证,则基于镜像id配置仓库认证

配置:

  • *:匹配所有远程仓库
  • external *:匹配所有不再本机上的远程仓库(也就是说,使用localhost的除外,使用file://协议的除外)
  • repo1,repo2:匹配repo1和repo2,使用逗号分割多个远程仓库
  • *,! repo1:匹配所有仓库,repo1除外

镜像常见做法是结合私服,使用私服代理任何外部的公共仓库

由于镜像仓库完全屏蔽了被镜像仓库,当镜像仓库不稳定或停止服务时,Maven仍将无法访问被镜仓库,因而无法下载构件

仓库搜索服务

  • nexus
  • jarvana
  • mvnbrowser
  • mvnrepository

生命周期

Maven生命周期是抽象的,实际行为都由插件来完成。生命周期和插件两者协同工作,密不可分。

Maven声明周期就是为了对搜友的构建过程进行抽象和统一,几乎所有的项目的构建都能映射到一个声明周期上。

生命周期抽象了构建的各个步骤,定义了它们的次序,但是没有提供具体的实现。

每个构建步骤都可以绑定一个或者多个插件行为,而且Maven为大多数构建步骤编写并绑定了默认步骤

Maven 有三个标准的生命周期,三套生命周期是相互独立的:

  • clean:项目清理的处理

  • default(或 build):项目部署的处理

  • site:项目站点文档创建的处理

每个生命周期包好一些阶段,这些阶段是有顺序的,并且后面的阶段依赖于前面的阶段,用户和Maven最直接的交互方式就是调用这些生命周期阶段

clean 生命周期

clean 生命周期包含3个阶段

  1. pre-clean:执行一些需要在clean之前完成的工作
  2. clean:移除所有上一次构建生成的文件
  3. post-clean:执行一些需要在clean之后立刻完成的工作

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(部署) 将最终的项目包复制到远程仓库中与其他开发者和项目共享。

site 生命周期

Maven Site 插件一般用来创建新的报告文档、部署站点等。包含4个阶段

  • pre-site:执行一些需要在生成站点文档之前完成的工作

  • site:生成项目的站点文档

  • post-site: 执行一些需要在生成站点文档之后完成的工作,并且为部署做准备

  • site-deploy:将生成的站点文档部署到特定的服务器上

用于建立和发布项目站点,Maven能够基于POM所包含的信息,自动生成一个友好的站点,方便团队交流和发布项目信息

插件

插件以独立的构件形式存在,Maven只会在需要的时候下载并使用构件。对于构件本身,为了能够复用代码,往往能够完成多个任务。

插件目标使用方式:mvn [plugin-name]:[goal-name]

mvn clean:clean

绑定

生命周期的阶段与插件的目标相互绑定,以完成某个具体的构建任务

Maven在核心为一些主要的生命周期阶段绑定了很多插件的目标,当用户通过命令行调用生命周期阶段的时候,对应插件 目标就会执行相应的任务。

生命周期与阶段与插件目标的绑定关系

项目的打包类型会影响构建的具体过程,因此,default生命周期的阶段与插件目标的绑定关系也由项目打包类型所决定。

自定义绑定

POM中build元素下的plugins子元素中声明插件的使用。

下每个子元素元素可以用来配置执行一个任务。

**即使不通过phase元素配置生命周期阶段,插件目标也能够绑定到生命周期中去。**因为很多插件的目标在编写时已经定义了默认绑定阶段。

当生命周期绑定到不同的生命周期阶段的时候,执行顺序由生命周期阶段的先后顺序决定。当多个插件目标绑定到同一个阶段时,这些插件声明的先后顺序决定了目标的执行顺序

配置

插件目标都支持从命令行配置,通过参数-D参数键=参数值的形式。参数-D是java自带的,其功能是通过命令行设置一个java系统属性。Maven简单的使用了该参数,在准备插件的时候检查系统属性,便实现了插件参数的配置。

在POM中可以一次性配置全局参数。同时还可以为某个插件任务配置特定的参数,通过对绑定到的多个生命周期阶段配上不同的配置,就可以让Maven在不同的生命周期阶段执行不同的任务。

配置特定任务的配置,而非插件整体的配置。

插件信息

命令行参数是由插件参数的表达式(Expression)决定的,并不是所有插件目标参数都有表达式,一些插件目标参数只能在POM中配置

通过maven-help-plugin插件能够获取插件的详细信息

# 获取插件信息。结果中最重要的是目标前缀(Goal Prefix),其作用是方便在命令行直接运行插件
mvn help:describe -Dplugin=groupId:artifactId:version

# 可以省略版本信息,自动获取最新版本
mvn help:describe -Dplugin=groupId:artifactId

# 可以使用插件前缀替换坐标
mvn help:describe -Dplugin=goalPrefix

# 添加goal参数,仅获取某个插件目标的信息
mvn help:describe -Dplugin=goalPrefix -Dgoal=goalName

# 添加detail参数,获取更加详细的信息
mvn help:describe -Dplugin=goalPrefix -Ddetail

命令行调用

Maven支持这种方式是因为有些任务不适合绑定到生命周期上。例如maven-help-plugin:describe

为了达到命令间接的目的,Maven引入了目标前缀的概念。通过目标前缀,Maven就能找到对应的artifactId

解析机制

为了方便用户使用和配置插件,Maven不需要用户提供完整的插件坐标信息,就可以解析得到正确的插件。

仓库

POM中元素下元素配置插件仓库信息。

子元素同依赖仓库。

在POM配置插件的时候,如果该插件时Maven的官方插件(即groupId时org.apache.maven.plugins),可以省略groupId的配置。但不推荐这一机制

版本计息

在用户没有提供插件版本的情况下,Maven会自动解析插件版本。

  • Maven在超级POM中为所有核心插件设定了版本
  • 如果该插件不属于核心插件的范畴,Maven就会检查所有仓库中可用的版本,然后做出选择。

不推荐依赖Maven解析插件版本

前缀解析

插件前缀与groupId、artifactId时一一对应的,这种匹配关系存储在仓库元数据中。groupId/maven-metadata.xml

Maven在解析插件仓库元数据的时候,会默认使用org.apache.maven.plugin和org.codehaus.mojo两个groupId,可以通过配置settgins.xml()让Maven检查其他groupId上的插件仓库元数据

  • 当Maven解析到dependency:tree这样的命令后,首先基于默认的groupId归并所有插件仓库的元数据org/apache/maven/plugins/aven-metadata.xml
  • 检查归并后的元数据,找到对应的artifactId为maven-dependency-plugin
  • 结合当前元数据的groupId
  • 根据仓库依赖解析机制的方法解析到version

聚合与继承

Maven的聚合特性能够把项目的各个模块聚合在一起构建,Maven的继承特性能帮助抽取各模块相同的依赖和插件等配置,在简化POM的同时,还能促进各个模块配置的一致性

聚合

对于聚合模块,其打包方式packaging的值必须为pom,否则就无法构建

元素时聚合的最核心的配置,用户可以通过在一个打包方式为pom的Maven项目中声明任意数量的元素来实现模块的聚合,这里每个model的值都是一个当前POM的相对目录

一般来说,为了方便快速定位内容,模块所处的目录名称应当与其artifactId一致

通常将聚合模块放在项目目录的最顶层,其他模块则为聚合模块的子目录存在。聚合模块与其他模块的目录结构并非一定要是父子关系

聚合模块仅仅是帮助聚合其他模块构建的工具,它本身并无实质的内容。

Maven首先会解析聚合模块的POM,分析要构建的模块,并计算出一个反应堆构建顺序(Reactor Build Order),然后根据这个顺序一次构建各个模块

Maven构建输出中显示的是各个模块的名字,而不是artifactId,为了让Maven的构建输出更清晰,应该在POM中配置合理的name字段

继承

在父POM中声明一些配置供子类POM继承,以实现“一处声明,多处使用”的目的

父模块POM的打包方式也必须是pom,由于父模块只是为了帮助消除配置的重复,因此它本身不包含除了POM之外的项目文件。

元素声明父模块,元素下指定了父模块的坐标,这三个元素是必须的。表示父模块POM的相对路径

  • Maven首先会根据relativePath检查父POM,默认值为…/pom.xml
  • 从本地仓库查找

子模块隐式的从父模块继承了groupId和version两个元素

可继承的POM元素:

  • groupId:项目组ID
  • version:项目版本
  • description:项目描述信息
  • organization:组织信息
  • inceptionYear:创世年份
  • url:URL地址
  • developers:开发者信息
  • contributors:贡献者信息
  • descributionManagement:部署配置
  • issueManagement:缺陷跟踪系统信息
  • ciManagement:持续集成系统信息
  • scm:项目的版本控制系统信息
  • mailingLists:邮件列表信息
  • properties:自定义的Maven属性
  • dependencies:依赖配置
  • dependencyManagement:依赖关系配置
  • repositories:仓库配置
  • build:源码目录配置、输出目录配置、插件配置、插件管理配置等
  • reportiong:报告输出目录配置、报告插件配置等

依赖管理

Maven提供的dependencyManagement元素既能让子模块继承到父模块的依赖配置,又能保证子模块依赖使用的灵活性。在dependencyManagement元素下的依赖声明不会引入实际的依赖,不过它能够约束dependencies下的依赖使用

完整的依赖声明在父POM中,子模块只需要配置简单的groupId和artifactId就能获得对应的依赖信息,从而引入正确的依赖

dependencyManagement元素下通过import依赖范围,可以将目标POM中的dependencyManagement配置搭导入并合并到当前POM的dependencyManagement元素中。import范围依赖由于其特殊性,一般都是只想打包类型为pom的模块

插件管理

pluginManagement元素管理插件

聚合与继承的关系

聚合与继承是两个概念,其目的完全不同

为了方便,一个POM往往既是聚合POM,又是父POM

约定大于配置

原因:使用约定可以大量减少配置

常见约定:

  • 源码目录为:src/main/java
  • 编译输出目录:target/classes
  • 打包方式:jar
  • 包输出目录:target/

遵循约定虽然损失了一定的灵活性,但用户不能随意安排目录结构,但是却能大大减少配置

超级POM

任何一个Maven项目都隐式的继承自该POM,Maven所提倡的约定都是在超级POM中配置

超级POM在maven-model-builder-x.x.x.jar的org/apache/maven/model/pom-4.0.0.xml路径下

Maven设定核心插件的原因是防止由于某些插件版本的变化而造成构建不稳定

反应堆

反应堆(Reactor)是值所有模块组成的一个构建结构。对于多模块项目来说,反应堆就包含了个模块之间继承与依赖的关系,从而能够自动计算出合理的模块构建顺序。

Maven按顺序读取POM,如果该POM没有依赖模块,那么就构建该模块,否则就先构建其依赖模块,如果该依赖模块还依赖于其他模块,则进一步先构建该依赖的依赖

模块间的依赖关系会将反应堆构成一个有向非循环图(Directed Acyclic Graph,DAG),各个模块是该图的节点,依赖关系构成了有向边。这个图不允许出现循环

Maven提供了很多命令选项支持裁剪反应堆:

  • -am,–also-make:同时构建所列模块的依赖模块
  • -amd,-also-make-dependents:同时构建依赖于所列模块的模块
  • -pl,–project :构建指定的模块,模块间用逗号分割
  • -rf,-resume-from :在完整反应堆构建顺序上指定从模块开始构建

灵活运用上述四个参数,可以帮助我们跳过无需构建的模块,从而加速构建。在项目庞大,模块特别多的时候,这种效果就会异常明显。

测试

maven-surefire-plugin的test目标会自动执行测试代码路径(默认为src/main/test)下所有符合一组命名模式的测试类

  • Test*.java
  • *Test.java
  • *TestCase.java

可通过命令行中加入参数skipTests参数跳过测试。maven.test.skip参数同时控制了maven-compiler-plugin和maven-surefire-plugin插件,跳过了测试代码编译、执行(两个插件的命令行表达式都是maven.test.skip)。

动态指定测试用例

test参数指定要运行的测试用例的类名

  • 完整类名,类名匹配的测试类得到运行
  • *匹配零个或多个字符
  • 使用逗号可以分割多个测试用例

test参数的值必须匹配一个或多个测试类,否则会报错并导致构建错误。可以加上failIfNoTest=false参数,告诉maven-surefire-plugin插件即使没有测试也不要报错

包含和排除测试用例

maven-surefire-plugin允许用户通过配置自定义包含一些其他测试类,或排除一些符合默认命名模式的测试类。

元素下元素配置要包含的其他测试类

元素下元素配置要包含的其他测试类

测试报告

maven-surefire-plugin会在项目的target/surefire-reports目录下生成连各种格式的错误报告:

  • 简单文本格式
  • 与JUnit兼容的XML格式(为了支持工具的解析)

cobertura-maven-plugin插件与Coberture工具集成,用户可以为Maven项目生成测试覆盖率报告。文件生成在target/site/cobertura目录下。

mvn cobertura:cobertura

TestNG

TestNG在JUnit基础上增加了很多特性。允许用户使用一个名为testng.xml的文件来配置想要运行的测试集合。

TestNG相较于JUnit的一大优势在于它支持测试组的概念

特性

Maven为了支持构建的灵活性,内置了三大特性:属性、Profile、资源过滤

属性

Maven有6类属性

  • 内置属性:只要有两个常用的——${basedir} 项目根目录 ​,${version}项目版本
  • POM属性:对于POM文件中对应元素的值
  • 自定义属性:元素下自定义的属性
  • settings属性:与POM属性同理,用户使用以**settings.**开头的属性引用settings.xml文件中XML元素的值
  • Java系统属性:所有Java系统属性都可以使用Maven属性引用
  • 环境遍历属性:以**env.**开头的Maven属性引用

资源过滤

Maven属性默认只有在POM中才会被解析。

资源文件的处理起始时maven-resources-plugin做的事情,它的默认行为只是将项目主资源文件复制到代码编译输出目录中,将测试资源文件复制到测试代码编译输出目录中。通过开启资源过滤,就能够解析资源文件中的Maven属性了

Maven默认的住主资源目录和测试资源目录的定义都是在超级POM中,因此只要在此基础上加上配置即可

Profile

为了能让构建在各个环境下方便移植,Maven引入了profile概念。profile能够在构建的时候修改POM的一个子集,或者添加额外的配置元素。

还可以用来分离构建的一些比较耗时或者耗资源的行为,并给予更合适的构建频率

激活profile

  • 命令行激活:-P加上profile的id,多个id之间以逗号分割
  • settings文件显示激活:元素下子元素中设置profile的id
  • 系统属性激活:<变量名>,当系统属性存在时自动激活(多个profile可以使用同一个系统属性来激活)
  • 操作系统环境激活:<操作系统属性名>,family属性值包括Windows、UNIX、Mac等,其他的name、arch、version,用户可以通过查看环境中的系统属性获得
  • 文件存在与否激活:/
  • 默认激活:,如果POM中有任何一个profile通过以上其他任意一种方式被激活,默认激活配置就会失效
# 查看当前激活的profile
mvn help:active-profiles
# 查看当前所有的profiles
mvn help:all-profiles

Profile种类

  • pom.xml,只对当前项目有效
  • 用户settings.xml:对本机上该用户的所有Maven项目有效
  • 全局settings.xml:对本机上所有Maven项目有效

WEB资源过滤

与一般资源文件一样,web资源文件默认不会被过滤。开启一般资源文件的过滤也不会影响到web资源文件。

maven-war-plugin插件可对src/main/webapp资源目录开启过滤

项目站点

maven-site-plugin插件用于站点生成,在target/site目录下能够找到Maven生成的站点文件。

# 通过stage目标,将站点预发布至某个本地临时目录下
mvn site:stage -DstagingDirectory=D:\tmp

项目信息

默认情况下,Maven生成的站点包含了很多项目信息连接,这是由maven-project-info-reports-plugin插件生成的,该插件内置在maven-site-plugin插件中。该插件会基于POM配置生成以下信息报告:

  • 关于(about):项目描述,
  • 持续集成(CI):持续集成服务器信息,
  • 依赖(Dependencies):依赖信息,包括传递性依赖、依赖图、依赖许可、依赖大小、所包含类数目等
  • 依赖收敛:只针对多模块项目生成,提供了一些依赖健康状况分析
  • 依赖管理:基于项目的依赖管理配置生成的报告
  • 问题追踪:
  • 邮件列表:
  • 插件管理
  • 项目许可证:
  • 项目概述:包括坐标、名称、描述等
  • 项目团队:
  • 源码仓库:

Maven不会凭空生成信息,只有用户在POM中提供了相关配置后,站点才有可能包含这些信息的报告

项目报告插件

Maven3中需要在maven-site-plugin插件的元素下配置

  • maven-javadoc-plugin:基于项目源代码生成JavaDoc文档
  • maven-jxr-plugin:以web页面的形式将java源代码展现出来,aggregate配置可以在聚合模块上整合所有源码
  • maven-checkstyle-plugin:使用Sun定义的编码规范,自动检查代码规范。
    • confgi/sun_checks.xml:Sun定义的编码规范,默认值
    • config/maven_checks.xml:Maven社区定义的编码规范
    • config/turbine_checks.xml:Turbine定义的编码规范
    • config/avalon_checks.xml:Avalon定义的编码规范
    • scr/main/resource目录下自定义checkstyle/my_ckecks.xml规则
  • maven-pmd-plugin:PMD报告(PMD是一款java源码分析工具,能够找寻代码中的问题),CMD报告(代码拷贝复制的分析)
  • maven-changelog-plugin:基于版本控制系统中就近的变更记录生成三份变更报告(前提是配置正确的SCM信息)
    • Change Log:基于提交的变更报告
    • Developer Activity:基于作者的变更报告
    • File Activity:基于文件的变更报告
  • cobertura-maven-plugin:测试覆盖率报告

外观

src/site/site.xml中配置站点外观,所有站点使用的本地web资源都必须位于src/site/resources目录下

那么属性配置标题

配置站点头部左侧,默认显示项目名称

配置项目站点头部右侧

最新发布版本

最近发布时间

面包屑导航

皮肤

自定义站点皮肤:

  1. 选择要使用的站点皮肤构件
  2. 配置站点描述符的skin元素使用该构件

Maven官方提供了三款皮肤:

  • org.apache.maven.skins:maven-classic-skin(默认)
  • org.apache.maven.skins:maven-default-skin
  • org.apache.maven.skins:maven-stylus-skin

导航边栏

默认页面左边的边栏只会显示包含项目信息报告和其他报告的菜单

可通过在下

子元素加入自定义菜单。

站点描述符中的Maven属性会被自动解析至对应的值,ref用来引用Maven站点默认生成的页面

  • reports:项目报告菜单
  • parent:父模块连接的菜单
  • modules:包含所有子模块连接的菜单

自定义页面

Maven支持比较号的两种文档格式为APT(类似基于维基的文档格式,所有APT文档必须位于src/site/apt目录下)和FML(用来创建FAQ页面的XML文档格式,FML文档位于arc/site/fml目录下)

国际化

  1. 项目所有源码、文档等,都以UTF-8编码保存
  2. maven-site-plugin使用UTF-8编码读取所有源码及文档,并以UTF-8格式生成站点html文档
  3. 配置maven-site-plugin指定当地语言。

编写插件

https://maven.apache.org/plugin-developers/index.html

  1. 创建一个maven-plugin项目:packaging值为maven-plugin
  2. 为插件编写目标:每个插件都必须有一个或多个目标,Maven成为Mojo(Maven Old Java Object),编写插件的时候必须提供一个或多个继承自AbstractMojo的类
  3. 为目标提供配置点:提供可配置的参数
  4. 编写代码实现的目标行为:根据实际需要实现Mojo
  5. 错误处理及日志:Mojo发生异常时,根据情况控制Maven的运行状态
  6. 测试插件:编写自动化的测试代码测试行为

Maven插件项目的POM特殊地方:

  • packaging必须为maven-plugin,这种类型能控制Maven为其在声明周期阶段绑定插件处理相关的目标
  • maven-plugin-api依赖,包含插件开发所必须的类

Mojo

每个插件目标类都必须继承AbstractMojo并实现execute()方法,只有这样Maven才能识别该插件目标,并执行execute()方法中的行为。

每个Mojo类都必须使用@goal标注写明自己的目标名称

Mojo标注

Mojo和Parameter注解建议查看对应接口类,防止版本变动

@Mojo注解标记当前类为Mojo类

  • name:唯一必须声明的标注,目标名称
  • defaultPhase:默认将该目标绑定至Default生命周期的某个阶段
  • requiresDependencyResolution:在运行该Mojo之前必须解析依赖解析范围
  • requiresDependencyCollection:在运行该Mojo之前必须解析的依赖集合范围
  • instantiationStrategy:Mojo实例化策略。(仅支持per-lookupsingleton),默认per-lookup
  • executionStrategy:执行策略:once-per-session or always. 默认once-per-session
  • requiresProject:是否必须在一个Maven项目中运行,默认为true
  • requiresReports:是否要求项目报告已经生成,默认false
  • aggregator:当Mojo在多模块项目上运行时,使用该标注表示该项目只会在顶层模块运行,默认false
  • requiresDirectInvocation:当值为true时,该目标就智能通过命令行直接调用,默认为false
  • requiresOnline:是否要求Maven’必须时在线状态,默认为false
  • inheritByDefault:继承默认值,默认true
  • configurator:自定义配置器类
  • threadSafe:mojo线程安全(从Maven 3.x开始),默认false

Mojo参数

@Parameter将Mojo某个字段标注为可配置的参数,Maven支持种类多样的Mojo参数,包括单值的boolean、int、float、String、Date、File和URL,多值的数组、Collection、Map、Properties等

@Parameter标注提供了一些额外的属性,进一步自定义Mojo参数:

  • alias=“”:别名
  • property=“${aSystemProperty}”:属性检索值,可通过-D、setting属性、pom配置设置值
  • defaultValue=“aValue|${anExpression}”:默认值,可以是一个简单字面量,也可以是一个表达式
  • readonly:参数制度
  • required:参数必须

错误处理和日志

MojoFailureException异常,会显示“BUILD_FAILURE”的错误信息,表示在运行时发现了预期的错误

MojoExecutationException异常,会显示“BUILD_ERROR”的错误信息,表示在运行时发现了未预期的错误

AbstractMojo提供了一个getLog()方法,用户可以使用该方法获得一个Log对象,支持四种日志级别:debug、info、warn、error

插件测试

Maven社区有一个用来帮助插件继承测试的插件,maven-invoker-plugin

  • projectDirectory用来配置测试项目的目录
  • goals表示测试项目上要运行的Maven目标
  • postBuildHookScript表示测试完成后要运行的验证脚本(BashShell或Groovy)

Archetype

  • pom.xml:archetype自身pom文件
  • src/main/resources/archetype-resources/pom.xml:基于该archetype生成的项目的POM原型
  • src/main/resources/META-INF/maven/archetype-metadata.xml:archetype的描述符文件
  • src/main/resources/archetype-resources/**:其他需要包含在archetype中的内容

最重要的是archetype-metadata.xml描述符文件:1. 声明那些目录及文件应该包含在Archetype中,2. 这个Archetype使用那些属性参数

Mavem与Gradle

gradle基于groovy,灵活。https://docs.gradle.org/current/userguide/userguide.html

maven基于xml,标准

你可能感兴趣的:(Maven,java)