Maven的POM介绍

Maven系统

Posted by qin4zhang on February 29, 2020

注意

想法及时记录,实现可以待做。

Maven作为java的依赖管理和构建打包工具。本文将介绍下pom文件的有关内容。官方文档

什么是POM?

项目对象模型或POM是Maven中的基本工作单元。这是一个XML文件,其中包含有关项目的信息以及Maven用于构建项目的配置详细信息。它包含大多数项目的默认值。 例子是构建目录,它是target。 源目录是src/main/java; 测试源目录为src/test/java; 等等。 当执行任务或目标时,Maven在当前目录中查找POM。 它读取POM,获取所需的配置信息,然后执行目标。

可以在POM中指定的一些配置是项目依赖项,可以执行的插件或目标,构建配置文件等等。 也可以指定其他信息,例如项目版本,描述,开发人员,邮件列表等。

Super POM

Super POM是Maven的默认POM。 除非明确设置,否则所有POM都会扩展Super POM,这意味着Super POM中指定的配置将由您为项目创建的POM继承。

最小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>

项目继承

合并的POM中的元素如下:

  • 依赖关系
  • 开发者和贡献者
  • 插件列表
  • 具有匹配ID的插件执行
  • 插件配置
  • 资源

Super POM是项目继承的一个示例,但是,你也可以通过在POM中指定父元素来介绍自己的父POM,如以下示例所示。

示例1

场景

例如,让我们重用我们先前的工件com.mycompany.app:my-app:1。让我们介绍另一个工件com.mycompany.app:my-module:1。

<project>
  <modelVersion>4.0.0</modelVersion>
 
  <groupId>com.mycompany.app</groupId>
  <artifactId>my-module</artifactId>
  <version>1</version>
</project>

让我们指定其目录结构如下:

.
 |-- my-module
 |   `-- pom.xml
 `-- pom.xml

注意my-module/pom.xml是com.mycompany.app:my-module:1的POM,而pom.xml是com.mycompany.app:my-app:1的POM

解决方法

现在,如果要将com.mycompany.app:my-app:1转换为com.mycompany.app:my-module:1的父项目,我们将必须修改com.mycompany.app:my-module: 1的POM进行以下配置:

<project>
  <modelVersion>4.0.0</modelVersion>
 
  <parent>
    <groupId>com.mycompany.app</groupId>
    <artifactId>my-app</artifactId>
    <version>1</version>
  </parent>
 
  <groupId>com.mycompany.app</groupId>
  <artifactId>my-module</artifactId>
  <version>1</version>
</project>

注意,我们现在有一个添加的部分,即父部分。 本部分允许我们指定哪个项目是我们的POM的父对象。 为此,我们可以指定父POM的完全限定的项目名称。 通过此设置,我们的模块现在可以继承父POM的某些属性。

或者,如果我们希望groupId和/或模块的版本与其父模块相同,则可以在其POM中删除groupId和/或模块的版本标识。

<project>
  <modelVersion>4.0.0</modelVersion>
 
  <parent>
    <groupId>com.mycompany.app</groupId>
    <artifactId>my-app</artifactId>
    <version>1</version>
  </parent>
 
  <artifactId>my-module</artifactId>
</project>

这允许模块继承groupId和/或其父POM的版本。

示例2

场景

但是,如果父项目已经安装在我们的本地存储库中或位于该特定目录结构中(父pom.xml比该模块的pom.xml高一个目录),那将起作用。

但是,如果尚未安装父项,并且目录结构如以下示例所示,该怎么办?

.
 |-- my-module
 |   `-- pom.xml
 `-- parent
     `-- pom.xml

解决方法

为了解决这个目录结构(或任何其他目录结构),我们必须在我们的父节中添加元素。

<project>
  <modelVersion>4.0.0</modelVersion>
 
  <parent>
    <groupId>com.mycompany.app</groupId>
    <artifactId>my-app</artifactId>
    <version>1</version>
    <relativePath>../parent/pom.xml</relativePath>
  </parent>
 
  <artifactId>my-module</artifactId>
</project>

顾名思义,这是从模块的pom.xml到父级的pom.xml的相对路径。

项目聚合

项目聚合类似于项目继承。 但是,不是从模块中指定父POM,而是从父POM中指定模块。 这样,父项目现在可以知道其模块,并且如果对父项目调用了Maven命令,那么该Maven命令也将对父模块执行。 若要进行项目聚合,必须执行以下操作:

  • 将父POM的包装更改为值”pom”。
  • 在父POM中指定其模块的目录(子POM)。

示例3

场景

给定先前的原始工件POM和目录结构:

com.mycompany.app:my-app:1的POM

<project>
  <modelVersion>4.0.0</modelVersion>
 
  <groupId>com.mycompany.app</groupId>
  <artifactId>my-app</artifactId>
  <version>1</version>
</project>

com.mycompany.app:my-module:1的POM

<project>
  <modelVersion>4.0.0</modelVersion>
 
  <groupId>com.mycompany.app</groupId>
  <artifactId>my-module</artifactId>
  <version>1</version>
</project>

目录结构

.
 |-- my-module
 |   `-- pom.xml
 `-- pom.xml

解决方法

如果要将my-module聚合到my-app中,则只需修改my-app。

<project>
  <modelVersion>4.0.0</modelVersion>
 
  <groupId>com.mycompany.app</groupId>
  <artifactId>my-app</artifactId>
  <version>1</version>
  <packaging>pom</packaging>
 
  <modules>
    <module>my-module</module>
  </modules>
</project>

在修订的com.mycompany.app:my-app:1中,添加了包装部分和模块部分。 对于包装,其值设置为”pom”,对于模块部分,我们具有元素<module>my-module</module><module>的值是从com.mycompany.app:my-app:1到com.mycompany.app:my-module:1的POM的相对路径(实际上,我们使用模块的artifactId作为模块目录的名称 )。

现在,每当一个Maven命令处理com.mycompany.app:my-app:1时,同样的Maven命令也将针对com.mycompany.app:my-module:1运行。此外,某些命令(特别是目标)对项目聚合的处理方式有所不同。

示例4

场景

但是,如果我们将目录结构更改为以下内容,该怎么办:

.
 |-- my-module
 |   `-- pom.xml
 `-- parent
     `-- pom.xml

父POM如何指定其模块?

解决方法

答案? -通过指定模块的路径,与示例3相同。

<project>
  <modelVersion>4.0.0</modelVersion>
 
  <groupId>com.mycompany.app</groupId>
  <artifactId>my-app</artifactId>
  <version>1</version>
  <packaging>pom</packaging>
 
  <modules>
    <module>../my-module</module>
  </modules>
</project>

项目继承和项目聚合

如果您有几个Maven项目,并且它们都有相似的配置,则可以通过提取那些相似的配置并创建一个父项目来重构项目。 因此,您要做的就是让您的Maven项目继承该父项目,然后将这些配置应用于所有这些项目。

并且,如果您有一组一起构建或处理的项目,则可以创建一个父项目,并使该父项目将这些项目声明为其模块。这样,您只需要构建父级,其余的就可以了。

当然,您可以同时具有项目继承和项目聚合。 意思是,您可以让您的模块指定一个父项目,同时让该父项目将那些Maven项目指定为其模块。 您只需要应用所有三个规则:

  • 在每个子POM中指定其父POM是谁。
  • 将父POM包装更改为值”pom”。
  • 在父POM中指定其模块的目录(子POM)

示例5

场景

再次考虑先前的原始项目POM,

com.mycompany.app:my-app:1的POM

<project>
  <modelVersion>4.0.0</modelVersion>
 
  <groupId>com.mycompany.app</groupId>
  <artifactId>my-app</artifactId>
  <version>1</version>
</project>

com.mycompany.app:my-module:1的POM

<project>
  <modelVersion>4.0.0</modelVersion>
 
  <groupId>com.mycompany.app</groupId>
  <artifactId>my-module</artifactId>
  <version>1</version>
</project>

这次的目录结构为

.
 |-- my-module
 |   `-- pom.xml
 `-- parent
     `-- pom.xml

解决方法

要同时进行项目继承和聚合,您只需应用所有三个规则。

com.mycompany.app:my-app:1的POM

<project>
  <modelVersion>4.0.0</modelVersion>
 
  <groupId>com.mycompany.app</groupId>
  <artifactId>my-app</artifactId>
  <version>1</version>
  <packaging>pom</packaging>
 
  <modules>
    <module>../my-module</module>
  </modules>
</project>

com.mycompany.app:my-module:1的POM

<project>
  <modelVersion>4.0.0</modelVersion>
 
  <parent>
    <groupId>com.mycompany.app</groupId>
    <artifactId>my-app</artifactId>
    <version>1</version>
    <relativePath>../parent/pom.xml</relativePath>
  </parent>
 
  <artifactId>my-module</artifactId>
</project>

注意: 配置文件继承与POM本身使用的继承策略相同。

项目值与变量

Maven鼓励的一种做法是不要重复自己。 但是,在某些情况下,您需要在几个不同的位置使用相同的值。 为了帮助确保仅指定一次该值,Maven允许您在POM中使用您自己的变量和预定义的变量。

例如,要访问project.version变量,您可以这样引用它:

<version>${project.version}</version>

要注意的一个因素是,如上所述,这些变量是在继承后进行处理的。这意味着,如果父项目使用变量,则其在子对象(而不是父对象)中的定义将是最终使用的变量。

可用变量

项目模型变量

模型的任何值为单个值元素的字段都可以引用为变量。例如,${project.groupId}${project.version}${project.build.sourceDirectory}等。请参阅POM参考以查看属性的完整列表。

这些变量都由前缀project引用。您可能还会看到带有pom的引用。作为前缀,或者完全省略前缀-这些形式现在已弃用,不应使用。

特殊的变量

名称 含义
project.basedir 当前项目所在的目录。
project.baseUri 当前项目所在的目录,以URI表示。从Maven 2.1.0开始
maven.build.timestamp 表示构建开始(UTC)的时间戳。从Maven 2.1.0-M1开始

可以通过声明属性maven.build.timestamp.format来定制构建时间戳的格式,如下例所示:

<project>
  ...
  <properties>
    <maven.build.timestamp.format>yyyy-MM-dd'T'HH:mm:ss'Z'</maven.build.timestamp.format>
  </properties>
  ...
</project>

格式模式必须符合SimpleDateFormat API文档中给出的规则。如果该属性不存在,则格式默认为示例中已给定的值。

属性

您还可以将项目中定义的任何属性引用为变量。考虑以下示例:

<project>
  ...
  <properties>
    <mavenVersion>3.0</mavenVersion>
  </properties>
 
  <dependencies>
    <dependency>
      <groupId>org.apache.maven</groupId>
      <artifactId>maven-artifact</artifactId>
      <version>${mavenVersion}</version>
    </dependency>
    <dependency>
      <groupId>org.apache.maven</groupId>
      <artifactId>maven-core</artifactId>
      <version>${mavenVersion}</version>
    </dependency>
  </dependencies>
  ...
</project>

标准的目录结构

具有通用的目录布局,使熟悉一个Maven项目的用户可以立即在另一个Maven项目中感到宾至如归。优点类似于采用整个站点的外观。

目录 含义
src/main/java 应用程序源码
src/main/resources 应用程序资源
src/main/filters 资源过滤器文件
src/main/webapp Web应用程序源
src/test/java 测试源码
src/test/resources 测试资源
src/test/filters 测试资源过滤器文件
src/it 集成测试
src/assembly 程序集描述符
src/site 站点
LICENSE.txt 项目许可证
NOTICE.txt 项目的依赖项要求的注意事项和出处
README.txt 项目文档

在顶层,描述项目的文件:pom.xml文件。此外,还有一些文本文档,供用户在接收到以下来源后即可立即阅读:README.txtLICENSE.txt等。

此结构只有两个子目录:srctarget。在这里唯一可以预期的其他目录是元数据,例如CVS.git.svn,以及多项目版本中的任何子项目(每个项目均如上所述)。

target目录用于容纳构建的所有输出。

src目录包含用于构建项目的所有源材料,其站点等。 它包含每种类型的子目录:main用于主构建工件,用于单元测试代码和资源的测试,站点等等。