Maven 是一个强大的 Java 软件项目构建工具。当然,我们也可以用其它语言构建项目,但是 Maven 是用 Java 开发的,因此历史上更多用于 Java 项目。本教程的目的是让我们理解 Maven 的工作机制,因此重点介绍 Maven 的核心概念。一旦理解了核心概念,就可以很轻松在 Maven 文档中或者在互联网上找到更多详细信息。

实际上,Maven 开发者声称 Maven 不仅仅是个构建工具。从Maven 的哲学这篇文档中,可以读到他们所信奉的。但是现在,我们只把它当作是一个构建工具。一旦理解了它,并开始使用它,我们就会搞清楚 Maven 到底是什么。

Maven官网

Maven 的官网为:http://maven.apache.org。我们可以在官网上下载最新版本的 Maven(目前最新版是 3.8.1)。

什么是构建工具

构建工具是把与创建软件项目有关的所有事情都自动化的一种工具。构建软件项目通常包含如下一到多项活动:

  • 生成源代码(如果在项目中用到了自动生成的代码)。
  • 从源代码生成文档。
  • 编译源代码。
  • 将编译后的代码打包为 JAR 文件或者 ZIP 文件。
  • 将打包好的代码安装到服务器上的一个仓库中或者其他地方。

有些软件项目可能比上述活动更多一些。这些活动通常可以插入到一个构建工具中,从而也可以自动化。

自动化构建过程的好处是,能降低手动创建软件时人为造成错误的风险。此外,自动化构建工具通常比人手动执行同样的步骤要快一些。

安装 Maven

要把 Maven 安装到自己的系统(计算机)中,请到Maven 下载页,按照指令下载。通常,我们需要做的是:

  1. 设置 JAVA_HOME 环境变量指向一个有效的 Java SDK(比如,Java 8)。
  2. 下载并解压 Maven。
  3. 设置 M2_HOME 环境变量指向解压 Maven 的目录。
  4. 设置 M2 环境变量指向 M2_HOME/bin(Windows 上是 %M2_HOME%\bin,Linux 上是 $M2_HOME/bin)。
  5. M2 添加到环境变量 PATH(Windows 上是 %M2%,Linux 上是 $M2)。
  6. 打开命令行提示符,键入 mvn -version 并回车。

在键入了 mvn -version 命令后,我们应该能看到 Maven 执行,并将 Maven 的版本号输出到命令行控制台。

注意:Maven 在执行时要用到 Java,所以必须安装好了 Java 环境。Maven 3.0.5 需要 Java 1.5 或者之后版本。我们这里使用Maven 3.3.3 + Java 8 (u45)。

Maven 概述 - 核心概念

Maven 是以 POM(Project Object Model,项目对象模型)文件的概念为中心。POM 文件是源代码、测试代码、依赖(所用的外部 Jar 文件)等项目资源的 XML 表示。这个 POM 文件包含了对所有这些资源的引用。它应该放在项目的根目录下。

如下图形阐述 Maven 如何使用 POM 文件,以及 POM 文件主要包含哪些东西:

1. Maven教程 - 图1

这些概念我们先概述如下,稍后会分别用一节详细解释。

  • POM文件:在执行一条 Maven 命令时,我们要给 Maven 一个 POM 文件,然后 Maven 会在 POM 中描述的资源上执行命令。
  • 构建生命周期、阶段和目标:Maven 中的构建过程被分成构建生命周期、阶段和目标。一个构建生命周期由一序列构建阶段组成,每个构建阶段又由一序列目标组成。当执行 Maven 时,我们是给 Maven 传递一条命令。这个命令就是一个构建生命周期、阶段或者目标的名称。如果一个生命周期被请求执行,那么该生命周期中所有的构建阶段就会被执行。如果一个构建阶段被请求执行,那么构建阶段的预定义序列中在它之前的所有构建阶段也都被执行。
  • 依赖和仓库:Maven 执行的首要目标之一是检查项目所需的依赖。依赖就是我们项目中所用的外部 JAR 文件(Java 库)。如果依赖在本地 Maven 仓库中没有找到,那么 Maven 就会从一个中央 Maven 仓库中下载它们,并把它们放在我们自己的本地仓库中。本地仓库只是我们计算机硬盘上的一个目录。可以自己指定本地仓库的位置,还可以指定使用哪个远程仓库来下载依赖。这些都会在本教程稍后更详细解释。
  • 构建插件:构建插件用于将额外的目标插入到一个构建阶段中。如果我们想为项目执行标准 Maven 构建阶段和目标没有覆盖的一组行为,我们可以将一个插件添加到 POM 文件中。Maven 有一些我们可以使用的标准插件,我们也可以根据自己的需要用 Java 实现自己的插件。
  • 构建配置文件:如果我们需要以不同的方式构建项目,就可以用构建配置文件。例如,我们也许需要为本地计算机上的开发和测试构建我们的项目,还需要在产品环境上部署来构建它。这两种构建可能是不同的。为启动不同的构建,我们可以给 POM 文件添加不同的构建配置文件。当执行 Maven 时,我们可以告诉 Maven 使用哪个构建配置文件。

Maven 与 Ant 对比

Ant 是 Apache 的另一个流行的构建工具。如果习惯了用 Ant,而且正试着学习 Maven,就会注意到二者的差异。
Ant 使用命令式方式,就是说我们在 Ant 构建文件中指定 Ant 应该采取什么行动。我们可以指定底层行为,比如复制文件、编译代码等等。我们指定这些行为,还可以指定它们执行的顺序。Ant 没有默认的目录结构。

Maven 使用更声明式的方式,也就是说我们可以在 POM 文件中指定要构建什么,而不是如何去构建它。POM 文件描述项目的资源,而不是如何去构建它。相反,Ant 文件描述如何构建项目。在 Maven 中,如何构建项目是预定义在 Maven 构建生命周期、阶段和目标中的。

Maven POM 文件

Maven POM 文件是一个 XML 文件,是一个描述项目用到的资源,源代码、测试代码等所在的位置、项目有什么外部依赖(JAR 文件)等。

POM 文件描述的是要构建什么,但是通常不会描述如何构建它。如何构建它是由 Maven 构建阶段和目标来决定。不过,如果需要的话,可以将自定义行为(目标)插入到 Maven 构建阶段。

每个项目都有一个 POM 文件。POM 文件的名称为 pom.xml,应该放在项目的根目录中。被划分为子项目的项目通常会有一个父项目的 POM 文件,每个子项目有一个 POM 文件。这种结构既允许整个项目一步就构建完成,也允许单独构建任何子项目。

本节的其余部分我们将描述 POM 文件的最重要的部分。POM 文件的完整参考,请查看Maven POM参考指南

如下是一个最小的 POM 文件:

  1. <project xmlns="http://maven.apache.org/POM/4.0.0"
  2. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  3. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
  4. http://maven.apache.org/xsd/maven-4.0.0.xsd">
  5. <modelVersion>4.0.0</modelVersion>
  6. <groupId>com.jenkov</groupId>
  7. <artifactId>java-web-crawler</artifactId>
  8. <version>1.0.0</version>
  9. </project>

其中:

  • modelVersion 元素设置我们正在用 POM 模型的什么版本。要使用匹配我们正在用的那一个 Maven 版本。版本 4.0.0 匹配 Maven 版本 2 和版本 3。
  • groupId 元素是一个组织或者一个项目(比如一个开源项目)的唯一标识号。通常我们会用与项目的根 Java 包名一样的名称。比如,对于 Java Web 爬虫项目,我们通常会选用 groupIDcom.16ketang。如果该项目是一个有很多独立贡献者的开源项目,可能用与项目相关(比如 com.javawebcrawler),而不是与公司相关的 groupID,会更有意义一些。groupID 不必是 Java 包名,也不需要用点符号来分隔 ID 中的单词。不过,如果确实要用 Java 包名以及点符号分隔的话,项目将会用匹配 groupID 的目录结构放在 Maven 仓库中。此时,每个 . 用一个目录分隔符来替换,并且每个单词表示为一个目录。因此,groupIDcom.16ketang 会放在目录 MAVEN_REPO/com/16ketang 中。目录名中的 MAVEN_REPO 部分会被替换为 Maven 仓库的目录路径。
  • artifactId 元素包含了正在构建的项目的名称。在我们的 Java Web Carwler 项目中,artifactID 将是 java-web-crawlerartifactID 也被用作为在构建项目时生成的 JAR 文件的名称的一部分。构建过程的输出,也就是构建结果,在 Maven 中称为构件(artifact)。它通常是一个 JAR、WAR 或者 EAR 文件,不过也可以是其它文件。
  • version 元素包含了项目的版本号。如果项目已经发布了不同的版本,比如一个开源 API,那么这个版本号就对构建进行版本设置很有用。通过用这种方式,项目的用户可以引用项目的指定版本。版本号被用作为 artifactID 目录下子目录的名称。版本号还被用作为所构建的构件的名称的一部分。

上述 groupIdartifactIdversion 元素会导致创建一个 JAR 文件,并把该文件放在如下路径中的本地 Maven 仓库中(目录和文件名):

MAVEN_REPO/com/16ketang/java-web-crawler/1.0.0/java-web-crawler-1.0.0.jar

如果项目使用Maven目录结构,而且项目没有外部依赖,那么上面的 POM 文件就是构建项目所需的所有东西了。

如果项目没有遵循标准目录结构,有外部依赖,或者在构建期间需要特殊的动作,就需要给 POM 文件添加更多元素。这些元素在 Maven POM 参考中列出来了(参见上面的链接)。

一般来说,我们可以在 POM 文件中指定很多东西,给 Maven 更多关于如何创建项目的细节。请参考 Maven POM 参考来查看有关可以指定什么的更多信息。

父 POM

所有 Maven POM 文件都继承自一个父 POM。如果没有指定父 POM,那么 POM 文件就继承自根 POM。如下是一个阐述这些继承关系的图示:

1. Maven教程 - 图2

可以让一个 POM 文件显式继承另一个 POM 文件。通过这种方式,我们可以通过父 POM 更改所有继承它的 POM 的设置。我们可以像这样,在 POM 文件的顶部指定父 POM:

<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
                      http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>my-parent</artifactId>
        <version>2.0</version>
        <relativePath>../my-parent</relativePath>
    </parent>


    <artifactId>my-project</artifactId>
    ...
</project>

继承的 POM 文件可以重写来自父 POM 的设置,只需要在继承的 POM 文件中指定新的设置即可。

POM 继承也在 Maven POM 参考中更详细讲解了。

有效的 POM

由于这种 POM 继承关系,当 Maven 执行时,可能很难知道完整的 POM 文件是什么样子。完整的 POM 文件(所有继承的结果)被称为有效的 POM(effective POM)。我们可以用如下命令,让 Maven 展示有效的 POM:

mvn help:effective-pom

这条命令会让 Maven 将有效 POM 输出到命令行控制台。

Maven 配置文件

Maven有两个配置文件。在配置文件中,我们可以为 Maven 配置跨所有 Maven POM 文件的设置。例如,我们可以配置:

  • 本地仓库的位置
  • 当前活动的构建配置文件
  • 等等。

这个配置文件叫做 settings.xml。两个配置文件放在:

  • Maven 安装目录:$M2_HOME/conf/settings.xml
  • 用户的 home 目录:${user.home}/.m2/settings.xml

这两个文件都是可选的。如果两个文件都存在,那么用户主目录设置文件中的值会覆盖 Maven 安装设置文件中的值。

我们可以在Maven设置参考中读到更多有关 Maven 配置文件的信息。

运行 Maven

在安装好 Maven,创建完 POM 文件,并把 POM 文件放在项目的根目录后,我们就可以在项目上运行 Maven了。

在命令行提示符上执行 mvn 命令就可以运行 Maven。当执行 mvn 命令时,我们要传递 Maven 要执行的构建生命周期、阶段或者目标的名称给它。例如:

mvn install

这条命令执行构建阶段 installdefault 构建生命周期的一部分),这个构建阶段会构建项目,复制打包好的 JAR 文件到本地 Maven 仓库。实际上,这条命令在执行 install 构建阶段之前,会执行在构建阶段序列中 install 之前的所有构建阶段。

我们可以通过传递多个参数给 mvn 目录,执行多个构建生命周期或者阶段。例如:

 mvn clean install

这条命令首先执行 clean 构建生命周期,从 Maven 输出目录中删除掉编译好的类,然后执行 install 构建阶段。

我们还可以通过传递用一个 : 分隔的构建阶段和目标名给 Maven 命令作为参数,来执行一个 Maven 目标(一个构建阶段的子部分)。例如:

mvn dependency:copy-dependencies

这条命令执行 dependency 构建阶段的 copy-dependencies 目标。

Maven 目录结构

Maven 有一个标准目录结构。如果我们在项目中遵循这个目录结构的话,就不需要在 POM 文件中为源代码、测试代码等指定目录。

可以在 Apache 网站中的Maven 标准目录结构简介中查看完整的目录结构。

如下是最重要的目录:

- src
  - main
    - java
    - resources
    - webapp
  - test
    - java
    - resources

- target

src目录是源代码和测试代码的根目录。其中main目录是与应用程序本身(而不是测试代码)相关的源代码的根目录。test目录包含测试源代码。main下的java目录包含应用程序本身的Java代码,test下的java目录包含测试有关的Java代码。

resources目录包含项目所需的其它资源。可以是一个应用程序的国际化所用的属性文件或者其它文件。

webapp目录包含我们的 Java Web 应用程序(如果项目是一个 Web 应用程序的话)。然后该目录会是 Web 应用程序的根目录。因此,webapp 目录包含 WEB-INF 目录等等。

target是 Maven 创建的。它包含Maven生成的所有编译好的类、JAR文件等。当执行 clean 构建阶段时,就是清空 target 目录。

项目依赖

除非项目很小,否则项目可能需要打包为JAR文件的外部Java API或者框架。这些JAR文件在编译项目代码时,需要在classpath上。

让这些外部JAR文件的版本保持最新是一件常见的任务。每个外部JAR可能还需要其它外部JAR文件等。递归下载所有这些外部依赖(JAR文件),并确保下载正确的版本是很麻烦的事情。特别是项目变得越来越大,外部依赖越来越多时更麻烦。

幸运的是,Maven有内置的依赖管理功能。我们可以在POM文件中指定项目依赖什么外部库,依赖哪个版本,然后Maven就会为我们下载它们,并把它们放在我们自己的本地Maven仓库中。如果外部库需要其它库,其它库也会被下载到本地Maven仓库中。

我们在POM文件的 dependencies 元素中指定项目依赖。如下是一个示例:

<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
   http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.jenkov.crawler</groupId>
    <artifactId>java-web-crawler</artifactId>
    <version>1.0.0</version>

      <dependencies>

        <dependency>
          <groupId>org.jsoup</groupId>
          <artifactId>jsoup</artifactId>
          <version>1.7.1</version>
        </dependency>

        <dependency>
          <groupId>junit</groupId>
          <artifactId>junit</artifactId>
          <version>4.8.1</version>
          <scope>test</scope>
        </dependency>

      </dependencies>


    <build>
    </build>

</project>

我们可以看到dependencies元素内有两个dependency元素。每个dependency元素描述一个外部依赖。

每个依赖由它的groupIdartifactIdversion来描述。我们应该还记得这也是在POM文件的开头标识我们自己的项目的方式。上面的示例需要org.jsoup组织的jsoup制品版本1.7.1,以及junit组织的junit制品版本4.8.1

当这个POM被Maven执行时,这两个依赖会从中央Maven仓库中下载下来,并放到我们的本地Maven仓库中。如果依赖已经在本地仓库中,Maven就不会下载它们。

有时,指定的依赖在中央Maven仓库中找不到。那么,我们就得自己下载依赖,然后把它放到本地Maven仓库中。记住要把它放在匹配groupIdartifactIdversion的子目录结构中。用/替换.,用/分隔groupIdartifactIdversion

上例中下载的两个依赖会被放在如下的子目录中:

MAVEN_REPOSITORY_ROOT/junit/junit/4.8.1

MAVEN_REPOSITORY_ROOT/org/jsoup/jsoup/1.7.1

外部依赖

Maven中的外部依赖是没有放在Maven仓库(不在本地、中央或者远程仓库)中的依赖(JAR文件)。它可能放在我们本地硬盘上的任何地方,比如一个web应用程序的lib目录中或者其它地方。因此“外部”意味着对Maven仓库系统是外部的,不仅仅是对项目是外部的。大多数依赖都是对项目是外部的,但是有一些是对仓库系统是外部的(在仓库中找不到)。

我们可以像这样配置一个外部依赖:

<dependency>
  <groupId>mydependency</groupId>
  <artifactId>mydependency</artifactId>
  <scope>system</scope>
  <version>1.0</version>
  <systemPath>${basedir}\war\WEB-INF\lib\mydependency.jar</systemPath>
</dependency>

这里,groupIdartifactId都被设置为依赖的名称,也就是使用的API的名称。scope元素值被设置为systemsystemPath元素被设置为指向包含依赖的JAR文件的位置。${basedir}指向POM所在的目录。路径的剩余部分是相对于该目录的。

快照依赖

快照依赖指的是还在开发中的依赖(JAR 文件)。与其不断更新版本号以得到最新版本,还不如依赖项目的快照版本。快照版本会在每次构建时总是下载到本地仓库中,即使一个匹配的快照版本已经放在本地仓库中。总是下载快照依赖能确保每次构建时,在本地仓库中总是有最新的版本。

我们只需要在 POM 文件的版本号后面附加上 -SNAPSHOT,就可以告诉 Maven 我们的项目是一个快照版本(这里我们也可以设置groupIdartifactId)。如下是一个version元素的示例:

<version>1.0-SNAPSHOT</version>

注意,-SNAPSHOT附加在版本号后面。

依赖于快照版本还可以通过在配置依赖的时候,将-SNAPSHOT附加在版本号之后来实现。例如:

<dependency>
    <groupId>com.jenkov</groupId>
    <artifactId>java-web-crawler</artifactId>
    <version>1.0-SNAPSHOT</version>
</dependency>

附加在version号后的-SNAPSHOT告诉Maven这是一个快照版本。

我们可以在Maven配置文件中配置Maven多久会下载快照依赖。

Maven仓库

Maven仓库是带有特殊元数据的打包好的JAR文件的目录。元数据就是POM文件,描述每个JAR文件属于哪个项目,每个JAR文件包含什么外部依赖。就是这个元数据让Maven能递归下载依赖的依赖,直到整个依赖树被下载下来,并放进本地仓库中。

有关Maven仓库的详细信息我们可以参考Maven官网上的Maven仓库介绍,这里我们做一个快速概述。

Maven有三类仓库,分别是:

  • 本地仓库
  • 中央仓库
  • 远程仓库

Maven按以上述顺序到这些仓库中搜索依赖。首先是在本地仓库中搜索,然后到中央仓库中,然后到远程仓库中(如果POM中指定了的话)。

下图阐述这三种类型的仓库及其位置:

1. Maven教程 - 图3

本地仓库

本地仓库是开发者电脑上的一个目录。这个仓库会包含 Maven 下载的所有依赖。同一个 Maven 仓库通常会被用于几个不同的项目。因此,如果多个项目需要某个依赖(比如,JUnit),Maven 只需要下载该依赖一次即可。

自己的项目也可以用 mvn install 命令,构建和安装在本地仓库中。通过这种方式,其它项目就可以在 Maven POM 文件内将它指定为外部依赖。

默认情况下,Maven 会将本地仓库放在本机的用户 home 目录内。不过,我们可以在 Maven 配置文件中设置一个目录,更改本地仓库的位置。Maven 配置文件也放在 user-home/.m2 目录中,名称为 settings.xml。如下是如何为本地仓库指定另一个位置的示例:

<settings>
    <localRepository>
        d:\data\java\products\maven\repository
    </localRepository>
</settings>

中央仓库

中央 Maven 仓库是由 Maven 社区提供的一个仓库。默认情况下,Maven 是在这个中央仓库中查找本地仓库中找不到的所有依赖,然后下载这些依赖到本地仓库中。访问中央仓库不需要特殊的配置。

远程仓库

远程仓库是放在 web 服务器上的仓库,Maven 可以像从中央仓库一样从这个仓库下载依赖。远程仓库可以放在互联网上任何地方,或者放在本地网络中。

远程仓库经常用于存放对组织内开放,被多个项目共享的项目。比如,通用安全项目可能要被多个内部项目所用。这个安全项目应该对外部世界是不可访问的,因而不应该放在公共的中央 Maven 仓库中,而是应该放在一个内部的远程仓库中。

远程仓库中找到的依赖也会被 Maven 下载并放到本地仓库中。

我们可以在 POM 文件中配置一个远程仓库。将如下的XML元素刚好放在 <dependencies> 元素之后:

<repositories>
   <repository>
       <id>16ketang.code</id>
       <url>http://maven.16ketang.com/maven2/lib</url>
   </repository>
</repositories>

Maven构建生命周期、阶段和目标

当 Maven 构建一个软件项目时,会遵循一个构建生命周期。构建生命周期被划分为多个构建阶段,构建阶段又被划分为多个构建目标。Maven 构建生命周期、构建阶段和构建目标详细描述在 Maven 官网上的Maven 构建阶段简介文档中,这里我们简单介绍一下。

构建生命周期

Maven 有三个内置的构建生命周期,分别是:

  1. default:处理与项目编译和打包有关的事情。
  2. clean:处理与从输出目录中删除临时文件(包括生成的源文件、编译好的类、之前的JAR文件等等)有关的事情。
  3. site:处理与生成项目文档有关的事情。实际上,site 可以为项目生成一个完整的文档网站。

这三个构建生命周期分别负责构建软件项目的不同方面。因此,三者是相互独立执行的。可以让 Maven 执行多个构建生命周期,但是它们会逐一执行,相互独立,就像分别执行两条 Maven 命令一样。

构建阶段

每个构建生命周期被划分为一序列构建阶段,构建阶段又被再划分为多个构建目标。因此,整个构建过程由一序列构建生命周期、构建阶段和构建目标组成。

我们可以执行一个完整的构建生命周期,比如 clean 或者 site;或者执行一个构建阶段,比如作为 default 构建生命周期一部分的 install;或者执行一个构建目标,比如 dependency:copy-dependencies。注意:不能直接执行 default 生命周期,必须指定 default 生命周期内的一个构建阶段或者构建目标。

当执行一个构建阶段时,在该标准阶段序列中的所有该构建阶段之前的构建阶段都要被执行。因此,执行 install 构建阶段其实是指先执行 install 阶段之前的所有构建阶段,然后再执行install 阶段。

default 生命周期是最有趣的,因为就是该生命周期构建代码。因为不能直接执行 default 生命周期,所以需要执行 default 生命周期内的构建阶段或者构建目标。default 生命周期有不少构建阶段和目标,所以这里我们不会描述所有阶段和目标。最常用的构建阶段包括:

构建阶段 描述
validate 验证项目的正确性以及所有所需信息可用,确保依赖被下载。
compile 编译项目的源代码。
test 使用合适的单元测试框架执行对被编译的源代码的测试。这些测试不应该需要代码被打包或者部署。
package 将编译好的代码打包成可分发的格式,比如JAR。
install 将包安装到本地仓库,给本地的其它项目用作依赖。
deploy 复制最终包到远程仓库,为与其它开发者和项目共享。

通过将这些构建阶段之一的名称传递给 mvn 命令,来执行该构建阶段。例如:

mvn package

这个例子会执行 package 构建阶段,因此 Maven 预定义构建阶段序列中它之前的所有构建阶段也会执行。

如果标准 Maven 构建阶段和目标不足以构建我们的项目,我们还可以创建 Maven 插件来添加所需的特殊构建功能。

构建目标

构建目标是 Maven 构建过程中最精细的步骤。一个构建目标可以绑定到一到多个构建阶段,或者完全不绑定到构建阶段。如果一个构建目标不绑定到任何构建阶段,那么我们只能通过将目标名称传递给 mvn 命令来执行它。如果一个构建目标被绑定到多个构建阶段,那么该目标会在它绑定的每一个构建阶段期间获得执行。

Maven 构建配置文件

Maven 构建配置文件让我们能使用不同的配置来构建项目。我们可以为不同的构建配置指定一个配置文件,并在需要的时候用这个构建配置文件构建项目,而不是创建两个单独的 POM 文件。

可以在 Maven 官网上的 Maven POM 参考中阅读详细的构建配置文件信息。这里我们只做一个快速概述。

Maven 构建配置文件是在 POM 文件中的 profiles 元素内指定的。每个构建配置文件被嵌套在一个 profile 元素内。如下是一个例子:

<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
   http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.jenkov.crawler</groupId>
  <artifactId>java-web-crawler</artifactId>
  <version>1.0.0</version>

  <profiles>
      <profile>
          <id>test</id>
          <activation>...</activation>
          <build>...</build>
          <modules>...</modules>
          <repositories>...</repositories>
          <pluginRepositories>...</pluginRepositories>
          <dependencies>...</dependencies>
          <reporting>...</reporting>
          <dependencyManagement>...</dependencyManagement>
          <distributionManagement>...</distributionManagement>
      </profile>
  </profiles>

</project>

构建配置文件描述在该构建配置文件之下执行时,POM 文件应该做何修改。可以是修改要用的应用程序配置文件。profile 元素内的元素会重写 POM 中更深一层的同名元素的值。

profile 元素内,我们可以看到一个 activation元素。这个元素描述触发要用的构建配置文件的条件。选择要执行什么配置文件的一种方法是在 settings.xml 文件中,这里我们可以设置当前活动的配置文件。另一个方法是在 Maven 命令行中添加 -P profile-name。更多信息请参见配置文件文档。

Maven 插件

Maven 插件让我们可以给构建过程添加我们自己的行为。通过创建继承一个特殊的 Maven 类的简单 Java 类,然后为该项目创建一个 POM 文件,就可以实现。插件应该放在它自己的项目中。

关于开发插件的更多信息,请参考Maven插件开发者中心