第1章 Maven简介
- 自Maven 2.0.9开始,所有核心的插件都设定了稳定版本,这意味着日常使用Maven时几乎不会受到不稳定插件的影响。此外,Maven社区也提倡为你使用的任何插件设定稳定的版本。从Maven 3开始,如果你使用插件时未设定版本,会看到警告信息。 P8
第2章 Maven的安装和配置
- 新的环境变量配置需要新的cmd窗口才能生效
第3章 Maven使用入门
- POM(Project Object Model,项目对象模型)
定义了项目的基本信息,用于描述项目如何构建,声明项目依赖等等。 - modelVersion指定了当前POM模型的版本,对应Maven 2及Maven 3来说,它只能是4.0.0
- SNAPSHOT意为快照,说明该项目还处于开发中,是不稳定的版本。
- test依赖范围表示该依赖只对测试有效,只能在测试代码中引用,不能在主代码中引用。如果不声明依赖范围,默认值是compile,表示该依赖对主代码和测试代码都有效。
- finalName可以自定义打包文件的名称,详见第14章。
第5章 坐标和依赖
- 当pom中不定义packaging时,Maven会使用默认值jar。
- packaging并非一定与构件的扩展名对应,比如packaging为maven-plugin的构件扩展名为jar。
- 依赖范围就是用来控制依赖与三种classpath(编译classpath、测试classpath、运行classpath)的关系。
- compile:编译依赖范围。如果没有指定,就会默认使用该依赖范围。使用此依赖范围的Maven依赖,对应编译、测试、运行三种classpath都有效。
- test:测试依赖范围。使用此依赖范围的Maven依赖,只对于测试classpath有效,在编译主代码或者运行项目时将无法使用此类依赖。
- provided:已提供依赖范围。使用此依赖范围的Maven依赖,对于编译和测试classpath有效,但在运行时无效。
- runtime:运行时依赖范围。使用此依赖范围的Maven依赖,对于测试和运行classpath有效,但在编译主代码时无效。
- system:系统依赖范围。该依赖范围与三种classpath的关系,和provided依赖范围完全一致。但是,使用system范围的依赖时必须通过systemPath元素显示地指定依赖文件的路径。由于此类依赖不是通过Maven仓库解析的,而且往往与本机系统绑定,可能造成构建的不可移植,因此应该谨慎使用。systemPath元素可以引用环境变量,如:
${java.home}
- import(Maven 2.0.9及以上):导入依赖范围。该依赖范围不会对三种classpath产生实际的影响。只在dependencyManagement元素下才有效果,使用该依赖范围的依赖通常指向一个POM,作用是将目标POM中的dependencyManagement配置导入并合并到当前POM的dependencyManagement元素中。P134
- 除import以外的各种依赖范围与三种classpath的关系如下表所示:
依赖范围(scope) | 对于编译classpath有效 | 对于测试classpath有效 | 对于运行时classpath有效 | 例子 |
---|---|---|---|---|
compile | Y | Y | Y | spring-core |
test | - | Y | - | JUnit |
provided | Y | Y | - | servlet-api |
runtime | - | Y | Y | JDBC驱动实现 |
system | Y | Y | - | 本地的,Maven仓库之外的类库文件 |
- 传递性依赖:Maven会解析各个直接依赖的POM,将那些必要的间接依赖以传递性依赖的形式引入到当前项目中。
- 传递性依赖范围,第一列表示第一直接依赖范围,第一行表示第二直接依赖范围。规律:当第二直接依赖依赖的范围是compile时,传递性依赖的范围与第一直接依赖的范围一致;当第二直接依赖的范围是test时,依赖不会得以传递;当第二直接依赖的范围是provided时,只传递第一直接依赖范围也为provided的依赖,且传递性依赖的范围同样为provided;当第二直接依赖的范围是runtime时,传递性依赖的范围与第一直接依赖的范围一致,当compile例外,此时传递性依赖的范围为runtime。
参考:http://seanzhou.iteye.com/blog/1688740
compile | test | provided | runtime | |
---|---|---|---|---|
compile | compile | - | - | runtime |
test | test | - | - | test |
provided | provided | - | provided | provided |
runtime | runtime | - | - | runtime |
- 依赖调解
从Maven 2.0.9开始,为了尽可能避免构建的不确定性,Maven定义了依赖调解的第二原则:第一声明者优先。在依赖路径长度相等的前提下,在POM中依赖声明的顺序决定了谁会被解析使用,顺序最靠前的那个依赖优胜。第一原则:路径最近者优先。 - 可选依赖不被传递
- 排除依赖
- 归类依赖,使用Maven属性
- 优化依赖
mvn dependency:list
,查看已解析依赖列表
mvn dependency:tree
,查看已解析依赖树
mvn dependency:analyze
,分析当前项目的依赖
显示声明任何项目中直接用到的依赖。
第6章 仓库
- 何为Maven仓库
得益于坐标机制,任何Maven项目使用任何一个构件的方式都是完全相同的。在此基础上,Maven可以在某个位置统一存储所有Maven项目共享的构件,这个统一的位置就是仓库。为了实现重用,项目构建完毕后生成的构件也可以安装或者部署到仓库中,供其他项目使用。 - 仓库的分类
本地仓库、远程仓库(中央仓库、私服、其他公共库) - 超级POM
$M2_HOME/lib/maven-model-builder-3.0.jar
中的org/apache/maven/model/pom-4.0.0.xml - 任何一个仓库声明的id必须是唯一的,尤其需要注意的是,Maven自带的中央仓库使用的id为central,如果其他的仓库声明也使用该id,就会覆盖中央仓库的配置。
- 远程仓库的认证
仓库信息可以直接配置在POM文件中,但是认证信息必须配置在settings.xml文件中。 - 快照版本
- 从仓库解析依赖的机制
RELEASE和LATEST版本,它们分别对应了仓库中存在的该构件的最新发布版本和最新版本(包含快照)。Maven 3不再支持在插件配置中石油LATEST和RELEASE。如果不设置插件版本,其效果就和RELEASE一样,Maven只会解析最新的发布版本构件。 - 镜像
如果仓库X可以提供仓库Y存储的所有内容,那么就可以认为X是Y的一个镜像。换句话说,任何一个可以从仓库Y获得的构件,都能够从它的镜像中获取。存在的意义:有的POM中指定了仓库,这样就可以在拦截去远程仓库的请求了。
It works like this: a POM may declare a repository to use in resolving certain artifacts. However, this repository may have problems with heavy traffic at times, so people have mirrored it to several places.
第7章 生命周期和插件
- Maven的生命周期是抽象的,其实际行为都是由插件来完成。
- 三套生命周期:clean、default和site
- clean生命周期
clean生命周期的目的是清理项目,它包含三个阶段:
- default生命周期
default生命周期定义了真正构建时所需要的执行的所有步骤,它是所有生命周期中最核心的部分,其包含的阶段如下,只对重要的阶段进行解释:
- site生命周期
site生命周期的目的是建立和发布项目站点,Maven能够基于POM所包含的信息,自动生成一个友好的站点,方便团队交流和发布项目信息。该生命周期包含如下阶段:
- clean生命周期
- 较之于生命周期阶段的前后依赖关系,三套生命周期本身是相互独立的,用户可以仅仅调用clean生命周期的某个阶段,或者仅仅调用default生命周期的某个阶段,而不会对其他生命周期产生任何影响。
当用户调用clean生命周期的clean阶段的时候,不会触发default生命周期的任何阶段,反之亦然,当用户调用default生命周期的compile阶段的时候,也不会触发clean生命周期的任何阶段。 - 插件目标:插件功能就是一个插件目标。
- 插件绑定,Maven的生命周期与插件相互绑定,用以完成实际的构建任务。
- 内置绑定,为了能让用户几乎不用任何配置就能构建Maven项目,Maven在核心为一些主要的生命周期阶段绑定了很多插件目标,当用户通过命令行调用生命周期阶段的时候,对应的插件目标就会执行相应的任务。P100
- 自定义绑定:除了内置绑定以外,用户还能够自己选择将某个插件目标绑定到生命周期的某个阶段上,这种自定义绑定方式能让Maven项目在构建过程中执行更多更富特色的任务。比如:使用
maven-source-plugin
创建项目的源码jar包。
- 对应自定义绑定的插件,用户总是应该声明一个非快照版本,这样可以避免由于插件版本变化造成的构建不稳定性。
- 有很多插件的目标在编写时已经定义了默认绑定阶段。
- 插件配置
- 命令行插件配置
- POM中插件全局配置
- POM中插件任务配置
- 从命令行调用,目标前缀(Goal Prefix)
- 插件的默认groupId
在POM中配置插件时,如果该插件是Maven的官方插件(即如果其groupId为org.apache.maven.plugin
),就可以省略groupId配置。虽然可以省略,但是不建议使用Maven这一机制,这样的配置会让团队不熟悉Maven的同学感到费解。 - 解析插件版本
Maven在超级POM中为所有核心插件设定了版本,超级POM是所有Maven项目的父POM,所有项目都继承这个超级POM的配置。
Maven 3调整了解析机制,当插件没有声明版本时,不再解析至latest,而是使用release。这样就可以避免由于快照频繁更新而导致的插件行为不稳定。 - 解析插件(目标)前缀
插件前缀与groupId:artifactId是一一对应的,这种匹配关系存储在仓库元数据中。
第8章 聚合与继承
- 聚合
- 打包方式packaging的值必须为pom
- 元素modules是实现聚合的最核心配置
- 继承
- 打包方式packaging的值必须为pom
- 使用parent元素声明父模块
- 可继承的POM元素,groupId、version、distributionManagement、properties、dependencies、dependencyManagement、build等
- Maven提供的dependencyManagement元素既能让子模块继承到父模块的依赖配置,又能保证子模块的依赖使用的灵活性。在dependencyManagement元素下的依赖声明不会引入实际的依赖,不过它能够约束dependencies下的依赖的使用。
- 插件管理,pluginManagement元素帮助管理插件。
- 聚合与继承的关系
聚合主要是为了方便快速构建项目,继承主要是为了消除重复配置。在实际项目中,一个POM即是聚合POM又是父POM。 - 约定由于配置(Convention Over Configuration)
- 超级POM说明 P141
- 反应堆(Reactor)
在一个多模块的Maven项目中,反应堆(Reactor)是指所有模块组成的一个构建结构。对于单模块的项目,反应堆就是该模块本身,但对于多模块项目来说,反应堆就包含了个模块之间继承与依赖的关系,从而能够自动计算出合理的模块构建顺序。
第14章 灵活的构建
- Maven属性
- 通过
<properties>
元素用户可以自定义一个或多个Maven属性,然后在POM的其他地方使用${属性名称}
的方式引用该属性,这种做法的最大意义在于消除重复。 - 内置属性:主要有两个常用内置属性——
${basedir}
表示项目的跟目录,即包含pom.xml文件的目录;${version}
表示项目版本。 - POM属性:用户可以使用该类属性引用POM文件中对应元素的值。例如
${project.artifactId}
就对应了<project><artifactId>
元素的值,常用的POM属性如下图所示,这些属性都对应了一个POM元素,他们中的一些属性的默认值都是在超级POM中定义的。
- 自定义属性:用户可以在POM的
<property>
元素下自定义Maven属性。例如:
然后在POM中其他地方使用${my.prop}
时被替换成hello。 - Settings属性:与POM属性同理,用户使用以
settings.
开头的属性引用settings.xml
文件中XML元素的值,如常用的${settings.localRepository}
指向用户本地仓库的地址。 - Java系统属性:所有Java系统属性都可以使用Maven属性引用,例如
${user.home}
指向了用户目录。可以使用mvn help:system
查看所有的Java系统属性。 - 环境变量属性:所有环境变量都可以使用以
env.
开头的Maven属性引用。例如${env.JAVA_HOME}
指代了JAVA_HOME环境变量的值。可以使用mvn help:system
查看所有的环境变量。
- 通过
- 构建环境的差异
- 资源过滤
- Maven Profile