天天看点

Maven实战(Maven In Action)

第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生命周期的目的是清理项目,它包含三个阶段:

      Maven实战(Maven In Action)
    • default生命周期

      default生命周期定义了真正构建时所需要的执行的所有步骤,它是所有生命周期中最核心的部分,其包含的阶段如下,只对重要的阶段进行解释:

      Maven实战(Maven In Action)
      Maven实战(Maven In Action)
    • site生命周期

      site生命周期的目的是建立和发布项目站点,Maven能够基于POM所包含的信息,自动生成一个友好的站点,方便团队交流和发布项目信息。该生命周期包含如下阶段:

      Maven实战(Maven In Action)
  • 较之于生命周期阶段的前后依赖关系,三套生命周期本身是相互独立的,用户可以仅仅调用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中定义的。
      Maven实战(Maven In Action)
    • 自定义属性:用户可以在POM的

      <property>

      元素下自定义Maven属性。例如:
      Maven实战(Maven In Action)
      然后在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