0%

pom 文件学习(未完待续)

前言

大概几十年前搞一个什么项目,研究 Makefile,看一些帖子说有 ant 这么一个东西,比 Makefile 要方便,然后又接触到了 mvn, 使用过 mvn install 这个命令—-现在好像这个 install 命令都不怎么看得到了 —- 一晃这么多年,又要和它打交道了,不过最近这一年来做 maven 项目,不知道看了多少遍官网了,感觉还是没有梳理清楚,这说明 maven 还真不是那么简单就能掌握的,老办法,还是要做做笔记整理整理,这篇文章记录对 pom 文件的学习。

(这里其实说错了,mvn install 是将 jar 包安装在本地的 maven 仓库中。 2020-09-24)

对于我来说,学习的思路,都是充分阅读官网(见参考),这个网页十分长,估计要分多次来记录笔记了。

博客

博客地址:IT老兵驿站

正文

先看一个 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
<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>

<!-- The Basics -->
<groupId>...</groupId>
<artifactId>...</artifactId>
<version>...</version>
<packaging>...</packaging>
<dependencies>...</dependencies>
<parent>...</parent>
<dependencyManagement>...</dependencyManagement>
<modules>...</modules>
<properties>...</properties>

<!-- Build Settings -->
<build>...</build>
<reporting>...</reporting>

<!-- More Project Information -->
<name>...</name>
<description>...</description>
<url>...</url>
<inceptionYear>...</inceptionYear>
<licenses>...</licenses>
<organization>...</organization>
<developers>...</developers>
<contributors>...</contributors>

<!-- Environment Settings -->
<issueManagement>...</issueManagement>
<ciManagement>...</ciManagement>
<mailingLists>...</mailingLists>
<scm>...</scm>
<prerequisites>...</prerequisites>
<repositories>...</repositories>
<pluginRepositories>...</pluginRepositories>
<distributionManagement>...</distributionManagement>
<profiles>...</profiles>
</project>

这是一个标准的 pom 文件的格式,摘自官网。

整篇文章就是围绕上面的这个格式来解释,分为了4个部分。

Basics 基础部分

Maven Coordinates 坐标

groupId、artifactId、version 是所有需要的字段,它们也可以从一个 parent 文件中继承,这个时候它们可以不被明确定义。这三个字段扮演的就像地址和时间戳,它们在 Maven 项目中就像坐标系统一样,在一个仓库里面指定了一个特定的位置。

groupId:在一个项目或者一个组织中是唯一的。

artifactId:制品Id是指项目的名字。

version:版本。

packaging

打包的目标,可用的有 pom、jar、maven-plugin、ejb、war、ear、rar。
默认是 jar。

POM 关系

One powerful aspect of Maven is its handling of project relationships: this includes dependencies (and transitive dependencies), inheritance, and aggregation (multi-module projects).

Maven 一个很强的地方是它的对于项目关系的处理,包含了依赖(transitive dependencies,在这里可能应该理解为传递依赖),继承,和聚合(多模块项目)。

Dependency management has a long tradition of being a complicated mess for anything but the most trivial of projects. “Jarmageddon” quickly ensues as the dependency tree becomes large and complicated. “Jar Hell” follows, where versions of dependencies on one system are not equivalent to the versions developed with, either by the wrong version given, or conflicting versions between similarly named jars.


Maven solves both problems through a common local repository from which to link projects correctly, versions and all.

这里面,Jarmageddon 和 Jar Hell 应该是两种常见的项目依赖的问题,不过我暂时没有找到准确的解释,先放一下。

Dependencies

这块可是复杂了,内容太多了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<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
https://maven.apache.org/xsd/maven-4.0.0.xsd">
...
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<type>jar</type>
<scope>test</scope>
<optional>true</optional>
</dependency>
...
</dependencies>
...
</project>

这是一个依赖的模板,这块内容非常多,看了几遍,暂时没有想到应该如何总结,可能回头单独总结了,尤其版本这块,和 js 的依赖关系是一样的,有各种规则,包含以下这些字段。

groupId, artifactId, version:

type:

scope:

systemPath:

optional:

Dependency Version Requirement Specification 依赖版本需求规格
Version Order Specification 版本的顺序规格
Version Order Testing 版本顺序测试
Exclusions 排除
Inheritance 继承

One powerful addition that Maven brings to build management is the concept of project inheritance. Although in build systems such as Ant, inheritance can certainly be simulated, Maven has gone the extra step in making project inheritance explicit to the project object model.

Maven 带来的一个强大的功能就是项目的继承。

1
2
3
4
5
6
7
8
9
10
11
<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
https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>org.codehaus.mojo</groupId>
<artifactId>my-parent</artifactId>
<version>2.0</version>
<packaging>pom</packaging>
</project>

The packaging type required to be pom for parent and aggregation (multi-module) projects. These types define the goals bound to a set of lifecycle stages. For example, if packaging is jar, then the package phase will execute the jar:jar goal. Now we may add values to the parent POM, which will be inherited by its children. Most elements from the parent POM are inherited by its children, including:

上面这段 xml 里面的 packaging 类型需要设置成 pom 类型,对于 parent 或者 aggregation 项目。这个类型定义了目标被约束在一套的生命阶段中。举例来说,如果 packaging 是 jar,那么
这个打包阶段将会执行 jar:jar 目标。

groupId
version
description
url
inceptionYear
organization
licenses
developers
contributors
mailingLists
scm
issueManagement
ciManagement
properties
dependencyManagement
dependencies
repositories
pluginRepositories
build
plugin executions with matching ids
plugin configuration
etc.
reporting
profiles

上面这些属性是可以被继承的。

artifactId
name
prerequisites

上面这些是不可以被继承的。

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
https://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>

Notice the relativePath element. It is not required, but may be used as a signifier to Maven to first search the path given for this project’s parent, before searching the local and then remote repositories.

relativePath 不是必须的,但是它可以作为一个记号,告诉 Maven 首先去哪里去搜索项目的 parent,可以是一个相对的路径,而不是去本地的 Maven 缓存或者远程的仓库中去寻找。

The Super POM 超级 POM

这里的概念和 Java 语言的概念是一样的,所有的 pom 都是继承自一个超级 pom,这个超级 pom 的内容态度,这里不复述了,参考这里

Dependency Management 依赖管理

Besides inheriting certain top-level elements, parents have elements to configure values for child POMs and transitive dependencies. One of those elements is dependencyManagement.

包含某些顶级元素在内,parent 可以给一些元素配置值来给 child POM 使用和实现一些依赖的传递。其中一个元素就是 dependencyManagement。

dependencyManagement: is used by a POM to help manage dependency information across all of its children. If the my-parent project uses dependencyManagement to define a dependency on junit:junit:4.12, then POMs inheriting from this one can set their dependency giving the groupId=junit and artifactId=junit only and Maven will fill in the version set by the parent. The benefits of this method are obvious. Dependency details can be set in one central location, which propagates to all inheriting POMs.

dependencyManagement:被 POM 用于在所有的孩子之间去帮助管理依赖信息。如果 my-parent 项目使用了 dependencyManagement 去定义一个依赖 junit:junit:4.12, 那么继承这个 POM 的孩子只用设置依赖 groupId=junit 和 artifactId=junit,不用设置版本。

Note that the version and scope of artifacts which are incorporated from transitive dependencies are also controlled by version specifications in a dependency management section. This can lead to unexpected consequences. Consider a case in which your project uses two dependences, dep1 and dep2. dep2 in turn also uses dep1, and requires a particular minimum version to function. If you then use dependencyManagement to specify an older version, dep2 will be forced to use the older version, and fail. So, you must be careful to check the entire dependency tree to avoid this problem; mvn dependency:tree is helpful.

注意在 dependency management 部分里面的这个 version 和制品的 scope(被传递合成进来的)也是被 version specifications 所控制。这有可能会引起一些预料外的结果。考虑一个问题,你的项目使用了2个依赖,dep1 和 dep2,dep2 也使用了 dep1,需要一个特别的小版本。如果你使用了 dependencyManagement 去指定一个更早的版本,dep2 将会被强迫使用这个较早的版本,并且会失败。所以,你必须小心地去检查完全的依赖树(entire dependency tree)去避免这个问题;mvn dependency:tree 会有帮助。

Aggregation (or Multi-Module) 聚合(或者多模块)

A project with modules is known as a multimodule, or aggregator project.

带有模块的项目被称为一个 multimodule,或者 aggregator 项目。这一部分好像暂时没有太多需要记录的。

Properties 属性

Properties are the last required piece to understand POM basics. Maven properties are value placeholder, like properties in Ant. Their values are accessible anywhere within a POM by using the notation ${X}, where X is the property. Or they can be used by plugins as default values, for example:

Properties 可以在一个 POM 文件的任意一个位置被访问到,通过使用 ${X}, X 就是这个属性。

1
2
3
4
5
6
7
8
9
10
<project>
...
<properties>
<maven.compiler.source>1.7</maven.compiler.source>
<maven.compiler.target>1.7</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
</properties>
...
</project>

They come in five different styles:


env.X: Prefixing a variable with “env.” will return the shell’s environment variable. For example, ${env.PATH} contains the PATH environment variable.
Note: While environment variables themselves are case-insensitive on Windows, lookup of properties is case-sensitive. In other words, while the Windows shell returns the same value for %PATH% and %Path%, Maven distinguishes between ${env.PATH} and ${env.Path}. The names of environment variables are normalized to all upper-case for the sake of reliability.

env.X:返回 shell 的环境变量。这个应该是在启动时读入虚拟机的。

project.x: A dot (.) notated path in the POM will contain the corresponding element’s value. For example: 1.0 is accessible via ${project.version}.

project.x:在 POM 文件中的以点表示的路径,访问的是对应的元素的值。

settings.x: A dot (.) notated path in the settings.xml will contain the corresponding element’s value. For example: false is accessible via ${settings.offline}.

settings.x:在 settings.xml 的原理同上面。

Java System Properties: All properties accessible via java.lang.System.getProperties() are available as POM properties, such as ${java.home}.

Java System Properties:Java 系统属性。

x: Set within a element in the POM. The value of value may be used as ${someVar}.

x:表示在 POM 文件的 元素内的值。

Build Settings 构建配置

Beyond the basics of the POM given above, there are two more elements that must be understood before claiming basic competency of the POM. They are the build element, that handles things like declaring your project’s directory structure and managing plugins; and the reporting element, that largely mirrors the build element for reporting purposes.

除了上面的配置,还有两个元素需要理解,build 和 reporting。
build 元素,处理生命你的项目目录,管理插件这些事情;
reporting 元素,映射了用于报告目的的构建元素;(这句话没有太理解,这个元素到底是做什么用的)

这两个元素似乎是作为插件来管理的,参考这里,父元素底下的元素是给这些插件使用的。

Build

According to the POM 4.0.0 XSD, the build element is conceptually divided into two parts: there is a BaseBuild type which contains the set of elements common to both build elements (the top-level build element under project and the build element under profiles, covered below); and there is the Build type, which contains the BaseBuild set as well as more elements for the top level definition. Let us begin with an analysis of the common elements between the two.

根据 POM 4.0.0 XSD, 这个 build 元素概念上分为两部分:在 project 下面的顶级元素 build,和在 profiles 里面的 build 元素。

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
https://maven.apache.org/xsd/maven-4.0.0.xsd">
...
<!-- "Project Build" contains more elements than just the BaseBuild set -->
<build>...</build>

<profiles>
<profile>
<!-- "Profile Build" contains a subset of "Project Build"s elements -->
<build>...</build>
</profile>
</profiles>
</project>

上面这两个 build 部分应该怎么理解呢?

The BaseBuild Element Set BaseBuild 元素集

1
2
3
4
5
6
7
8
9
<build>
<defaultGoal>install</defaultGoal>
<directory>${basedir}/target</directory>
<finalName>${artifactId}-${version}</finalName>
<filters>
<filter>filters/filter1.properties</filter>
</filters>
...
</build>

defaultGoal:默认目标。
directory:构建输出的目标目录,默认是在 ${basedir}/target。
finalName:最终构建的目标的名字。
filter:定义了哪些 *.properties 包含了 properties 的列表。默认的 filter 目录是 ${basedir}/src/main/filters/。

上面就是 BaseBuild 元素集。

除了这个,还有 Resources,Plugins,Plugin Management,Resources 比较简单,配置资源的一些属性,后面这两项内容比较多,看了几遍,还没有看明白。

More Project Information 更多的项目信息

Environment Settings 环境设置

总结

pom 的官网这篇文章非常长,就是因为太长了,所以,其实我断断续续,或者说断章取义地看过不少遍,但总是感觉没有看明白,还是需要系统地、具体地梳理一遍。

未完待续……

参考

https://maven.apache.org/pom.html
https://www.cnblogs.com/AlanLee/p/6132976.html 这个帖子和下面这个帖子讲的不错,不过又有一样的地方,不知道是谁借鉴谁
https://www.cnblogs.com/javahr/p/9328483.html
https://www.cnblogs.com/yjmyzz/p/3495762.html