Maven(1)_Maven基础

参考Maven入门指南Maven Getting Started GuideMaven Tutorial

Maven主要为开发者提供了一个可复用、可维护的工程模型,以及与基于这个模型的构建工具和一系列插件。

构建工具是将软件项目构建相关的过程自动化的工具。构建一个软件项目通常包含以下一个或多个过程:

  • 生成源码(如果项目使用自动生成源码);
  • 从源码生成项目文档;
  • 编译源码;
  • 将编译后的代码打包成JAR文件或者ZIP文件;
  • 将打包好的代码安装到服务器、仓库或者其它的地方;

有些项目可能需要更多的过程才能完成构建,这些过程一般也可以整合到构建工具中,因此它们也可以实现自动化。

自动化构建过程的好处是将手动构建过程中犯错的风险降到最低。而且,自动构建工具通常要比手动执行同样的构建过程要快。

核心概念

pom.xml

Maven工程结构和内容被定义在一个xml文件中 - pom.xml,也就是project object model,此文件是整个Maven系统的基础组件,描述了项目的资源,源码,测试代码,依赖等。pom.xml位于项目的根目录下。

在执行一条maven命令时,maven会读取项目的pom.xml文件,并根据pom.xml的相关内容执行命令。

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

Maven的构建过程从大到小被分为构建生命周期、阶段和目标,其关系为:

  • 一个生命周期包含若干个阶段
  • 一个阶段包含若干个目标

一般maven使用的命令形式为:mvn command,其中command命令就是构建生命周期、阶段或者目标的名字。如果command为一个生命周期,该生命周期的所有构建阶段都会被执行。如果command为一个生命周期具体的一个构建阶段,那么这个生命周期中,所有处于目标执行阶段之前的阶段以及该目标阶段都会被执行。

目标操作(goal)表示某个有助于项目构建和管理的特定的任务。

  • 一个目标操作可以绑定0到多个构建阶段。
  • 不绑定任何构建阶段的目标操作可以通过直接调用的方式执行。

执行的顺序取决于目标操作和构建阶段调用的次序。以下面的命令为例,参数clean和package是构建阶段而dependency:copy-dependencies是一个目标操作。

mvn clean dependency:copy-dependencies package

在这里,clean阶段会首先执行,然后是执行dependency:copy-dependencies目标操作,最后是执行package阶段。

依赖和仓库

一个大型项目一般都会需要依赖许多外部包,也就是这个项目的依赖。Maven设置了一个本地仓库,所有依赖都会被放在本地仓库(本地的一个目录)中。如果在本地仓库中不存在该依赖,则Maven会从中央仓库下载并放到本地仓库。

插件

Maven提供了一系列标准的构建生命周期和构建阶段、目标,如果仍无法满足项目构建的要求,可以使用查找并使用插件来满足需要。

Maven实际上是一个执行插件的框架,其所有的任务其实都是由插件完成。Maven插件通常用于:

  • 生成jar包文件
  • 生成war包文件
  • 编译源码文件
  • 代码单元测试
  • 生成项目文档
  • 生成项目报告

一个插件通常提供一系列的目标操作,并且目标操作可以通过以下格式的命令执行
mvn [插件名]:[目标操作名]
例如,一个Java项目可以通过运行下面的命令使用maven-compiler-plugin的compile目标操作编译。
mvn compiler:compile

另外插件目标也可以与绑定到构建阶段上(可以是现有的构建阶段)。这样在执行该构建阶段时,所绑定的目标也会一起被执行。

例如在执行构建阶段时如果需要输出信息,可以使用maven-antrun-plugin插件来打印数据到控制台。

创建下面的pom.xml文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<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.companyname.projectgroup</groupId>
<artifactId>project</artifactId>
<version>1.0</version>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.1</version>
<executions>
<execution>
<id>id.clean</id>
<phase>clean</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<tasks>
<echo>clean phase</echo>
</tasks>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

执行mvn clean.

Maven将会开始处理并且输出clean生命周期的clean阶段的信息。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
[INFO] Scanning for projects...
[INFO] ------------------------------------------------------------------
[INFO] Building Unnamed - com.companyname.projectgroup:project:jar:1.0
[INFO] task-segment: [post-clean]
[INFO] ------------------------------------------------------------------
[INFO] [clean:clean {execution: default-clean}]
[INFO] [antrun:run {execution: id.clean}]
[INFO] Executing tasks
[echo] clean phase
[INFO] Executed tasks
[INFO] ------------------------------------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO] ------------------------------------------------------------------
[INFO] Total time: < 1 second
[INFO] Finished at: Sat Jul 07 13:38:59 IST 2012
[INFO] Final Memory: 4M/44M
[INFO] ------------------------------------------------------------------

上面的例子中阐明了下面几个关键概念:

  • 插件在pom.xml文件中是通过plugins节点明确指定的。
  • 每个插件可以有多个目标操作。
  • 你可以使用phase节点来定义插件从哪个节点开始处理。我们已使用的是clean阶段。
  • 你可以通过绑定任务到插件的目标操作来配置要执行的任务。我们已经绑定了echo任务到maven-antrun-plugin插件的run目标操作。
  • 以上,Maven会处理剩下的事情。若本地仓库中找不到,Maven会下载插件,并且开始处理。

Maven提供了下面两类插件:

类型 描述
构建插件(Build plugins) 这类插件在构建过程中执行,并且应该配置在pom.xml文件的节点中。
报告插件(Reporting plugins) 这类插件在生成站点过程中执行,并且应该配置在pom.xml文件的节点中。

下面是一些常用的插件的列表:

插件 描述
clean 构建完成后清理目标,删除目标目录。
compiler 编译Java源文件。
surefile 运行JUnit单元测试,生成测试报告。
jar 从当前项目生成JAR文件。
war 从当前项目生成WAR文件。
javadoc 生成项目的Javadoc。
antrun 运行任意指定构建阶段的一系列ant任务。

配置文件

配置文件用于以不同的方式构建项目。比如可能需要在本地环境构建,用于开发和测试,也可能需要构建后用于开发环境。具体可以配置的一些内容包括:

  • 本地仓库的路径
  • 当前编译配置选项等

maven设置了两个配置文件,分别在:

  • maven安装目录下: $M2_HOME/conf/settings.xml
  • 用户主目录中: ${user.home}/.m2/settings.xml

如果两个文件都存在,则用户目录的配置会覆盖安装目下的配置。

在POM文件中增加不同的构建配置,可以启用不同的构建过程。当运行Maven时,可以指定要使用的配置。

POM

POM意为项目对象模型(Project Object Model),是Maven中基本单元。它是一个名为pom.xml的XML文件,总是存在于项目的更目录下。

POM包含了项目相关的信息和Maven用来构建一个或多个项目的各种配置详情。POM文件描述的是构建“什么”,而不是“如何”构建。如何构建是取决于Maven的构建阶段和目标。当然,如果需要,你也可以向Maven构建阶段中添加自定义的目标。

每一个项目都有一个POM文件。POM文件即pom.xml,应该放在项目的根目录下。一个项目如果分为多个子项目,一般来讲,父项目有一个POM文件,每一个子项目都有一个POM文件。在这种结构下,既可以一步构建整个项目,也可以各个子项目分开构建。

POM也包含了各种目标操作(goal)和插件。当执行一个任务或者目标操作时,Maven会查找当前目录下的POM。Maven读取POM,从中获得需要的配置信息,然后执行目标操作。部分Maven可以从POM中明确的配置列出如下:

  • 项目依赖(project dependencies)
  • 插件(plugins)
  • 目标操作(goals)
  • 构建(build profiles)
  • 项目版本(project version)
  • 开发者(developers)
  • 邮件列表(mailing list)

一个最基本的POM文件如下:

1
2
3
4
5
6
7
8
9
10
<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.mycompany.app</groupId>
<artifactId>my-app</artifactId>
<version>1.0</version>
</project>

groupID表示开发者或者开发公司的唯一ID,一般使用java包的根名作为groupID。artifactId一般是项目名。version指项目版本。

注意,项目在maven仓库的结构化目中,该结构化目录会与groupID匹配,每一个.会成为目录分隔符,每个词都表示一个目录。如groupID为com.plusaber项目将位于MAVEN_REPO/com/plusaber。类似的,artifactId也会成为MAVEN_REPO/com/plusaber的子目录,另外artifactId也是构建完项目后生成的jar包的文件名的一部分。

  • 父pom

所有的Maven pom文件都继承自一个父pom。如果没有指定父pom,则该pom文件继承自根pom。

可以在pom文件指定父pom:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<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>
...

子pom的配置会覆盖父pom的配置,由于继承和覆盖的原因,无法直接通过查看子pom和父pom了解最后的有效pom。这时可以使用mvn help:effective-pom打印出当前的有效pom文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
<?xml version="1.0" encoding="UTF-8"?>
<!-- ================================================================= -->
<!-- -->
<!-- Generated by Maven Help Plugin on 2012-07-05T11:41:51 -->
<!-- See: http://maven.apache.org/plugins/maven-help-plugin/ -->
<!-- -->
<!-- ================================================================= -->

<!-- ================================================================= -->
<!-- -->
<!-- Effective POM for project -->
<!-- 'com.companyname.project-group:project-name:jar:1.0' -->
<!-- -->
<!-- ================================================================= -->

<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 h
ttp://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.companyname.project-group</groupId>
<artifactId>project</artifactId>
<version>1.0</version>
<build>
<sourceDirectory>C:\MVN\project\src\main\java</sourceDirectory>
<scriptSourceDirectory>src/main/scripts</scriptSourceDirectory>
<testSourceDirectory>C:\MVN\project\src\test\java</testSourceDirectory>
<outputDirectory>C:\MVN\project\target\classes</outputDirectory>
<testOutputDirectory>C:\MVN\project\target\test-classes</testOutputDirectory>
<resources>
<resource>
<mergeId>resource-0</mergeId>
<directory>C:\MVN\project\src\main\resources</directory>
</resource>
</resources>
<testResources>
<testResource>
<mergeId>resource-1</mergeId>
<directory>C:\MVN\project\src\test\resources</directory>
</testResource>
</testResources>
<directory>C:\MVN\project\target</directory>
<finalName>project-1.0</finalName>
<pluginManagement>
<plugins>
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.3</version>
</plugin>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.2-beta-2</version>
</plugin>
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>2.2</version>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.0.2</version>
</plugin>
<plugin>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.0</version>
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.4</version>
</plugin>
<plugin>
<artifactId>maven-ear-plugin</artifactId>
<version>2.3.1</version>
</plugin>
<plugin>
<artifactId>maven-ejb-plugin</artifactId>
<version>2.1</version>
</plugin>
<plugin>
<artifactId>maven-install-plugin</artifactId>
<version>2.2</version>
</plugin>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<version>2.2</version>
</plugin>
<plugin>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.5</version>
</plugin>
<plugin>
<artifactId>maven-plugin-plugin</artifactId>
<version>2.4.3</version>
</plugin>
<plugin>
<artifactId>maven-rar-plugin</artifactId>
<version>2.2</version>
</plugin>
<plugin>
<artifactId>maven-release-plugin</artifactId>
<version>2.0-beta-8</version>
</plugin>
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>2.3</version>
</plugin>
<plugin>
<artifactId>maven-site-plugin</artifactId>
<version>2.0-beta-7</version>
</plugin>
<plugin>
<artifactId>maven-source-plugin</artifactId>
<version>2.0.4</version>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.4.3</version>
</plugin>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>2.1-alpha-2</version>
</plugin>
</plugins>
</pluginManagement>
<plugins>
<plugin>
<artifactId>maven-help-plugin</artifactId>
<version>2.1.1</version>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<snapshots>
<enabled>false</enabled>
</snapshots>
<id>central</id>
<name>Maven Repository Switchboard</name>
<url>http://repo1.maven.org/maven2</url>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<releases>
<updatePolicy>never</updatePolicy>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
<id>central</id>
<name>Maven Plugin Repository</name>
<url>http://repo1.maven.org/maven2</url>
</pluginRepository>
</pluginRepositories>
<reporting>
<outputDirectory>C:\MVN\project\target/site</outputDirectory>
</reporting>
</project>

在上面的完整的effective pom.xml中,你可以看到项目构建的所有信息,包括默认的源文件目录结构,输出路径,需要的插件,报告目录,这些信息Maven在执行期望的目标操作时都会用到。

Maven的pom.xml在大部分情况要求手动写。Maven提供了很多archetype插件用来创建项目以及按规则创建项目结构和pom.xml文件。

Maven命令

mvn command,其中command命令就是构建生命周期、阶段或者目标的名字。如果command为一个生命周期,该生命周期的所有构建阶段都会被执行。如果command为一个生命周期具体的一个构建阶段,那么这个生命周期中,所有处于目标执行阶段之前的阶段以及该目标阶段都会被执行。
mvn install
install是默认生命周期的一个阶段,具体任务包括编译项目,将打包的jar文件复制到本地仓库。事实上,在执行install之前,默认生命周期位于install的所有阶段都被执行。

我们可以向mvn命令传入多个参数,执行多个构建周期或阶段,如:
mvn clean install
clean是一个生命周期(简称周期),具体任务是删除maven输入目录中已编译的类文件,然后执行install构建阶段。一个一个顺序执行,互相没有影响。

也可以执行一个maven目标,这时参数需要将构建阶段与目标名以冒号相连。
mvn dependency:copy-dependencies,执行dependency构建阶段中的copy-dependencies目标。

Maven目录结构

maven的一个主要原则就是约定优先,maven设置了一个标准的目录结构,如果在项目中遵循Maven的目录结构,就无需在pom文件中指定源码测试代码等目录。

dir/file usage
src/main/java Application/Library sources
src/main/resources Application/Library resources
src/main/filters Resource filter files
src/main/webapp Web application sources
src/test/java Test sources
src/test/resources Test resources
src/test/filters Test resource filter files
src/it Integration Tests (primarily for plugins)
src/assembly Assembly descriptors
src/site Site
LICENSE.txt Project’s license
NOTICE.txt Notices and attributions required by libraries that the project depends on
README.txt Project’s readme

依赖

项目依赖

Maven提供了依赖管理的功能。你只需要在pom文件里指定依赖jar包的名称、版本号,Maven会自动下载并放到你的Maven本地仓库中。如果这些外部jar包依赖了其它的库,它们也会被下载到你的Maven本地仓库。

可以通过在pom文件添加dependencies属性中指定项目依赖。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<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.mycompany.app</groupId>
<artifactId>my-app</artifactId>
<version>1.0-SNAPSHOT</version>

<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.7.1</version>
</dependency>
</dependencies>
</project>
1
2
MAVEN_REPOSITORY_ROOT/junit/junit/4.11
MAVEN_REPOSITORY_ROOT/org/jsoup/jsoup/1.7.1

可以看到,每一个依赖也是由groupID,artifactId和version来描述,和pom文件开头用来标识项目的方式是一样的。

执行这个pom文件时,如果本地仓库已经有了这两个依赖,maven就不会去中央仓库下载(本地仓库的依赖可以被多个项目使用)。如果没有,maven则会去中央仓库寻找这些依赖并下载到本地仓库。

需要注意的是,有时候指定的依赖在maven的中央仓库里没有,这是我们需要手动下载这些依赖并放到mavne的本地仓库。这些依赖必须放到与groupId, artifactId和version匹配的字目录中,用/替换.并为每个字段创建相应目录。

外部依赖

Maven的外部依赖指的是不在Maven的仓库(包括本地仓库、中央仓库和远程仓库)中的依赖(jar包)。它可能位于你本地硬盘的某个地方,比如web应用的lib目录下。

可以配置外部依赖如下:

1
2
3
4
5
6
7
<dependency>
<groupId>mydependency</groupId>
<artifactId>mydependency</artifactId>
<scope>system</scope>
<version>1.0</version>
<systemPath>${basedir}\war\WEB-INF\lib\mydependency.jar</systemPath>
</dependency>

groupId和artifactId为依赖的名称,即API的名称。scope属性为system。systemPath属性为jar文件的路径。${basedir}为pom文件所在的目录,路径中的其它部分是相对于该目录而言的。

快照依赖

快照依赖指的是那些还在开发中的依赖(jar包)。与其经常地更新版本号来获取最新版本,不如你直接依赖项目的快照版本。快照版本的每一个build版本都会被下载到本地仓库,即使该快照版本已经在本地仓库了。总是下载快照依赖可以确保本地仓库中的每一个build版本都是最新的。

在pom文件的最开头(设置groupId和artifactId的地方),在版本号后追加-SNAPSHOT,则告诉Maven你的项目是一个快照版本。如:

<version>1.0-SNAPSHOT</version>

在配置依赖时,在版本号后追加-SNAPSHOT表明依赖的是一个快照版本。如:

1
2
3
4
5
<dependency>
<groupId>com.jenkov</groupId>
<artifactId>java-web-crawler</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>

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

Maven仓库

Maven仓库就是存储jar包和一些元数据信息的目录,一般是用于根目录下的.m2文件夹,比如/Users/admin/.m2。其中的元数据即pom文件,描述了该jar包属于哪个项目,以及jar包所需的外部依赖。该元数据信息使得Maven可以递归地下载所有的依赖,直到整个依赖树都下载完毕并放到你的本地仓库中。参考Introduction to Repositories

Maven有三种类型的仓库:

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

Maven根据以上的顺序去仓库中搜索依赖。首先是本地仓库,然后是中央仓库,最后,如果pom文件中配置了远程仓库,则会去远程仓库中查找。

本地仓库

本地仓库就是开发者电脑上的一个目录。该仓库包含了Maven下载的所有依赖。一般来讲,一个本地仓库为多个不同的项目服务。因此,Maven只需下载一次,即使有多个项目都依赖它(如junit)。

通过mvn install命令可以将你自己的项目构建并安装到本地仓库中。这样,你的其它项目就可以通过在pom文件将该jar包作为外部依赖来使用。

Maven的本地仓库默认在你本机的用户目录下。不过,你可以在Maven的配置文件中修改本地仓库的路径。Maven的配置文件也在用户目录下(user-home/.m2),文件名为settings.xml。以下示例为本地仓库指定其它的路径:

1
2
3
4
5
<settings>
<localRepository>
d:\data\java\products\maven\repository
</localRepository>
</settings>

中央仓库

Maven的中央仓库由Maven社区提供。默认情况下,所有不在本地仓库中的依赖都会去这个中央仓库查找。然后Maven会将这些依赖下载到你的本地仓库。访问中央仓库不需要做额外的配置。

远程仓库

远程仓库是位于web服务器上的一个仓库,Maven可以从该仓库下载依赖,就像从中央仓库下载依赖一样。远程仓库可以位于Internet上的任何地方,也可以是位于本地网络中。

远程仓库一般用于放置组织内部的项目,该项目由多个项目共享。比如,由多个内部项目共用的安全项目。该安全项目不能被外部访问,因此不能放在公开的中央仓库下,而应该放到内部的远程仓库中。

远程仓库中的依赖也会被Maven下载到本地仓库中。可以在pom文件里配置远程仓库。将以下的xml片段放到属性之后:

1
2
3
4
5
6
<repositories>
<repository>
<id>jenkov.code</id>
<url>http://maven.jenkov.com/maven2/lib</url>
</repository>
</repositories>

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

当使用Maven构建项目时,会遵循一个构建生命周期。该生命周期分为多个构建阶段,而构建阶段又分为多个构建目标。参考Introduction to the Build Lifecycle

构建生命周期

Maven有三个内嵌的构建生命周期:clean, default, site.

每一个构建生命期关注项目构建的不同方面。因此,它们是独立地执行的。Maven可以执行多个生命期,但是它们是串行执行的,相互独立,就像你执行了多条独立的Maven命令。

Clean生命周期

当我们执行mvn的post-clean命令时,Maven调用clean生命周期,它包含以下阶段:

  • pre-clean
  • clean
  • post-clean

Maven的clean目标操作(clean:clean)在clean生命周期中被绑定到clean阶段。clean:clean 目标操作通过删除构建目录来删除一个项目构建的输出文件。这样,当mvn clean命令执行时,Maven会删除构建目录。

default生命周期

构建生命周期是Maven的最主要的生命周期,用来构建应用。default生命期关注的是项目的编译和打包。clean生命期关注的是从输出目录中删掉临时文件,包括自动生成的源文件、编译后的类文件,之前版本的jar文件等。site生命期关注的是为项目生成文档。实际上,site可以使用文档为项目生成一个完整的网站。

构建阶段

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

你可以执行一个构建生命期,如clean或site,一个构建阶段,如default生命期的install,或者一个构建目标,如dependency:copy-dependencies。注意:你不能直接执行default生命期,你需要指定default生命期中的一个构建阶段或者构建目标。

当你执行一个构建阶段时,所有在该构建阶段之前的构建阶段(根据标准构建顺序)都会被执行。因此,执行install阶段,意味着所有位于install阶段前的构建阶段都会被执行,然后才执行install阶段。

default生命期更多的关注于构建代码。由于你不能直接执行default生命期,你需要执行其中一个构建阶段或者构建目标。default生命期包含了相当多的构建阶段和目标,这里不会所有都介绍。最常用的构建阶段有:

  • validate - validate the project is correct and all necessary information is available
  • compile - compile the source code of the project
  • test - test the compiled source code using a suitable unit * testing framework. These tests should not require the code be packaged or deployed
  • package - take the compiled code and package it in its distributable format, such as a JAR.
  • integration-test - process and deploy the package if necessary into an environment where integration tests can be run
  • verify - run any checks to verify the package is valid and meets quality criteria
  • install - install the package into the local repository, for use as a dependency in other projects locally
  • deploy - done in an integration or release environment, copies the final package to the remote repository for sharing with other developers and projects.

完整的default周期的阶段:

生命周期阶段 描述
validate(校验) 校验项目是否正确并且所有必要的信息可以完成项目的构建过程。
initialize(初始化) 初始化构建状态,比如设置属性值。
generate-sources(生成源代码) 生成包含在编译阶段中的任何源代码。
process-sources(处理源代码) 处理源代码,比如说,过滤任意值。
generate-resources(生成资源文件) 生成将会包含在项目包中的资源文件。
process-resources (处理资源文件) 复制和处理资源到目标目录,为打包阶段最好准备。
compile(编译) 编译项目的源代码。
process-classes(处理类文件) 处理编译生成的文件,比如说对Java class文件做字节码改善优化。
generate-test-sources(生成测试源代码) 生成包含在编译阶段中的任何测试源代码。
process-test-sources(处理测试源代码) 处理测试源代码,比如说,过滤任意值。
test-compile(编译测试源码) 编译测试源代码到测试目标目录.
process-test-classes(处理测试类文件) 处理测试源码编译生成的文件。
test(测试) 使用合适的单元测试框架运行测试(Juint是其中之一)。
prepare-package(准备打包) 在实际打包之前,执行任何的必要的操作为打包做准备。
package(打包) 将编译后的代码打包成可分发格式的文件,比如JAR、WAR或者EAR文件。
pre-integration-test(集成测试前) 在执行集成测试前进行必要的动作。比如说,搭建需要的环境。
integration-test(集成测试) 处理和部署项目到可以运行集成测试环境中。
post-integration-test(集成测试后) 在执行集成测试完成后进行必要的动作。比如说,清理集成测试环境。
verify (验证) 运行任意的检查来验证项目包有效且达到质量标准。
install(安装) 安装项目包到本地仓库,这样项目包可以用作其他本地项目的依赖。
deploy(部署) 将最终的项目包复制到远程仓库中与其他开发者和项目共享。

构建目标

构建目标是Maven构建过程中最细化的步骤。一个目标可以与一个或多个构建阶段绑定,也可以不绑定。如果一个目标没有与任何构建阶段绑定,你只能将该目标的名称作为参数传递给mvn命令来执行它。如果一个目标绑定到多个构建阶段,该目标在绑定的构建阶段执行的同时被执行。

Maven构建配置

Maven构建配置使你能使用不同的配置来构建项目。不用创建两个独立的pom文件。你只需使用不同的构建配置指定不同的配置文件,然后使用该配置文件构建项目即可。

关于构建配置的详细信息可以参考Maven POM参考的Profile部分。这里是一个快速的介绍。

Maven的构建配置在pom文件的profiles属性中指定,例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<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插件,可以向构建过程添加自定义的动作。创建一个简单的Java类,该类继承一个特殊的Maven类,然后为项目创建一个pom文件。该插件应该位于其项目下。可以参考Plugin Developers Centre