POM(Project Object Model)是 Maven 工程的工作基础,以 pom.xml 的形式存在于项目中,在这里配置构建工程的详细信息。它为大多数项目都预先配置了一些默认值,如构建目录 build,源码目录 src/main/java,测试源码目录 src/test/java 等等。
这里对如何进行最常用的依赖与插件的配置作简单的记录。
Super POM(顶层 POM)
Super POM 是 Maven 默认的 POM,所有的 POM 都默认继承这个 POM。其实这就有点类似 Java 中的 Object 类。
查看详细的 Super POM 配置
而我们的工程的 POM 要求以下几个元素是必须的
project root
modelVersion - 应被设置为 4.0.0
groupId - 项目组 id
artifactId - 项目 id
version - 项目版本
一个例子
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.mycompany.app</groupId>
<artifactId>my-app</artifactId>
<version>1</version>
</project>
1
2
3
4
5
6
工程继承
假设你有一个项目 com.mycompany.app:my-app:1 项目结构如下
.
|-- my-module
| `-- pom.xml
`-- pom.xml
1
2
3
4
其中 my-module 的 pom.xml 配置如下
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.mycompany.app</groupId>
<artifactId>my-module</artifactId>
<version>1</version>
</project>
1
2
3
4
5
6
如果我们想要 my-module 继承上级工程的 pom 配置,则可将 pom.xml 改为如下
<project>
<parent>
<groupId>com.mycompany.app</groupId>
<artifactId>my-app</artifactId>
<version>1</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>com.mycompany.app</groupId>
<artifactId>my-module</artifactId>
<version>1</version>
</project>
1
2
3
4
5
6
7
8
9
10
11
此外,如果我们希望工程的 groupId 跟 version 保持与父工程一致,则可去掉 groupId 跟 version
<project>
<parent>
<groupId>com.mycompany.app</groupId>
<artifactId>my-app</artifactId>
<version>1</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>my-module</artifactId>
</project>
1
2
3
4
5
6
7
8
9
如果项目结构是下面这样的
.
|-- my-module
| `-- pom.xml
`-- parent
`-- pom.xml
1
2
3
4
5
则 my-module 工程的 pom 配置如下
<project>
<parent>
<groupId>com.mycompany.app</groupId>
<artifactId>my-app</artifactId>
<version>1</version>
<relativePath>../parent/pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>my-module</artifactId>
</project>
1
2
3
4
5
6
7
8
9
10
通过 <relativePath> 元素指定父工程 pom 文件的路径
依赖配置
简单的配置
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
1
2
3
4
5
6
一个依赖至少包括 groupId、artifactId、version 三个元素,如果该依赖不是 jar 类型,则需要指定 type ,默认是 jar。如果是 war ,则需指定 <type>war<type> 。
scope 表示在什么时候需要使用到该依赖,并会影响传递依赖
scope 的可选值有:
compile
当 scope 未指定时的默认值,在编译,测试,运行时都需要,在所有的类路径都是可用的。
provided
类似 compile,表示你希望在运行时由 JDK 或者容器去提供这些依赖。例如,当构建一个 web 项目的时候,我们会设置 Servlet API 相关的依赖的 scope 为 provided,因为这些类应该由容器提供。
runtime
表示依赖在项目运行时需要被使用。
test
表示依赖在测试的时候需要被使用。
system
类似于 provided,但是本地依赖,有时候我们用到一些远程仓库中没有的依赖,就需要使用这个 scope,表示使用本地的依赖。
import (在 Maven 2.0.9 或更高版本中可用)
此 scope 仅支持 pom 文件中 type 配置为 pom 的依赖,并只能在 <dependencyManagement> 中使用。相当于引入依赖管理。
由于依赖传递的特性,依赖会自动包含相关的依赖,有时候我们想使用不同版本的依赖,则可排除掉传递依赖,如
<project>
...
<dependencies>
<dependency>
<groupId>group-a</groupId>
<artifactId>artifact-a</artifactId>
<version>1.0</version>
<exclusions>
<!-- 排除 artifact-a 所依赖的 excluded-artifact -->
<exclusion>
<groupId>group-c</groupId>
<artifactId>excluded-artifact</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>group-a</groupId>
<artifactId>artifact-b</artifactId>
<version>1.0</version>
<!-- 不是 jar 类型,需要指定类型 -->
<type>bar</type>
<scope>runtime</scope>
</dependency>
</dependencies>
</project>
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
Dependency Management
当我们有几个 Maven 工程有相似的依赖的时候,我们可以创建一个父项目,配置这些公共的依赖,然后让这些工程继承父项目的配置,就能够节省配置代码量,并方便统一管理版本。
比如我们有 3 个工程 A,B,C,然后这 3 个工程都使用了 JUnit,则可创建一个工程 parent,并配置依赖
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>maven</groupId>
<artifactId>parent</artifactId>
<packaging>pom</packaging>
<version>1.0</version>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
然后在 A,B,C 中配置 <parent> 即可继承 JUnit 的依赖 。
有一种情况是,A,B 需要使用 JUnit,C 不需要使用,但我们还是需要在父工程进行统一管理,那我们就需要配置 <dependencyManagement> 元素如下
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>maven</groupId>
<artifactId>parent</artifactId>
<packaging>pom</packaging>
<version>1.0</version>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>com.test</groupId>
<artifactId>project1</artifactId>
<version>1</version>
</dependency>
<dependency>
<groupId>com.test</groupId>
<artifactId>project2</artifactId>
<version>1</version>
</dependency>
</dependencies>
</project>
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
在 <dependencyManagement> 中的依赖,只是进行管理,但并不引入。比如我们工程 A,B 需要使用 JUnit,则配置
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>maven</groupId>
<artifactId>A(or B)</artifactId>
<packaging>jar</packaging>
<version>1.0</version>
<parent>
<groupId>maven</groupId>
<artifactId>parent</artifactId>
<version>1</version>
</parent>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
</dependencies>
</project>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
这里不需要为依赖制定版本号,因为已经在父工程指定。
而 C 工程只要不配置 JUnit 依赖,就不会引入 JUnit。
插件配置
Maven 所有的工作都是由插件完成的,插件分为两类
Build plugins 在构建项目的时候执行,应该被配置在 <build> 元素中
Reporting plugins 在生成站点的时候执行,应该被配置在 <reporting> 元素中
所有的插件配置要求有三个信息:groupId , artifactId ,version ,这跟依赖的配置相似。类似 <dependencyManagement> , 插件配置也有 <pluginManagement> ,用法也一样,参考依赖管理。
一个普通的配置看起来如下:
<project>
...
<build>
<plugins>
<plugin>
<artifactId>maven-myquery-plugin</artifactId>
<version>1.0</version>
<configuration>
<url>http://www.foobar.com/query</url>
<timeout>10</timeout>
<options>
<option>one</option>
<option>two</option>
<option>three</option>
</options>
</configuration>
</plugin>
</plugins>
</build>
...
</project>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<configuration> 里面的元素对应插件目标的参数,如果想知道某个插件目标的可用参数,通常可以通过下面的命令查询
mvn <pluginName>:help -Ddetail -Dgoal=<goalName>
比如想知道 install 插件的 install 目标的参数,则可执行命令
mvn install:help -Ddetail -Dgoal=install
会看到如下的输出
这里写图片描述
插件目标的配置
通常我们需要配置插件目标执行时的参数,看下面的例子
<project>
...
<build>
<plugins>
<plugin>
<artifactId>maven-myquery-plugin</artifactId>
<version>1.0</version>
<executions>
<execution>
<id>execution1</id>
<phase>test</phase>
<configuration>
<url>http://www.foo.com/query</url>
<timeout>10</timeout>
<options>
<option>one</option>
<option>two</option>
<option>three</option>
</options>
</configuration>
<goals>
<goal>query</goal>
</goals>
</execution>
<execution>
<id>execution2</id>
<configuration>
<url>http://www.bar.com/query</url>
<timeout>15</timeout>
<options>
<option>four</option>
<option>five</option>
<option>six</option>
</options>
</configuration>
<goals>
<goal>query</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
...
</project>
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
即将 <configuration> 置于 <execution> 标签中,<execution> 标签中通过配置 <phase> 、<goal> 分别指定了配置应用的阶段和目标,如例子中的 id 为 execution1 的配置会应用在 test 阶段中的 query 目标中。我们可以看到 id 为 execution2 的 <execution> 中没有 phase 标签,那么它会在什么时候应用呢?
如果该目标默认绑定了一个阶段,则在这个阶段应用。
如果该目标没有默认的绑定,则不会应用。
这里的 <id>execution1</id> 有什么用呢?其实当我们执行一条命令时,像
mvn maven-myquery-plugin:query
这时它会应用什么配置呢?如果在 <executions> 外有配置,则会应用,如果没有,则上面配置的 <execution> 并不会应用上,那么如果我们希望执行上面配置好参数的目标,那么可以加上 id 执行,如
mvn maven-myquery-plugin:query@execution1
执行时就会应用上 execution1 的配置。
忽略继承
默认情况下,子工程会继承父工程的插件配置,如果不希望继承,则可配置 <inherited> 标签
<project>
...
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.2</version>
<inherited>false</inherited>
...
</plugin>
</plugins>
</build>
...
</project>