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>
工程继承
- 假设你有一个项目 com.mycompany.app:my-app:1 项目结构如下
.
|-- my-module
| `-- pom.xml
`-- pom.xml
其中 my-module 的 pom.xml 配置如下
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.mycompany.app</groupId>
<artifactId>my-module</artifactId>
<version>1</version>
</project>
如果我们想要 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>
此外,如果我们希望工程的 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>
- 如果项目结构是下面这样的
.
|-- my-module
| `-- pom.xml
`-- parent
`-- pom.xml
则 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>
通过 <relativePath>
元素指定父工程 pom 文件的路径
依赖配置
简单的配置
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
一个依赖至少包括 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>
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>
然后在 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>
在 <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>
这里不需要为依赖制定版本号,因为已经在父工程指定。
而 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>
<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>
即将 <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>