观察我们创建的项目就可以发现,无论是父模块还是子模块,都包含一个pom.xml
配置文件,接下来我们将要学习POM
的相关知识。
项目对象模型(Project Object Model)也成为POM
,是Maven
项目的基本单位。
POM
是以.xml
配置文件的形式存在于项目中的,它包含了项目信息以及构建项目的配置详情。当项目去执行一个任务或目标时,Maven
会在当前目录寻找POM
并且读取信息以及配置,最后去执行相应的功能。
POM
可以指定配置信息,如项目的依赖,插件等,也可以制定项目的信息,如版本、描述,开发人员等,可以说没有POM
就没有Maven
。
1. 快速预览
以下是POM
元素的清单
<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>
<!-- 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>
可以看到,官方给这些元素分为几部分
- 基础元素 The Basics
- 构建设置 Build Settings
- 项目额外信息 More Project Infomation
- 环境设置 Environment Settings
2. 基础元素
2.1 最少配置项
POM
至少应该包含如下内容
project
: 整个POM
的根modelVersion
:模型版本,现在都是固定4.0.0
groupId
:项目所属组的ID,一般为项目所属的公司、机构、个人的名称/网站倒叙 + 项目所属租名,如org.springframework.boot
,com.google.guava
。
其中spring
的网站为http://springframework.org
,与现在的http://spring.io
通用,倒过来就是org.springframework
,项目为spring boot
所属组名为boot
,所以完整的groupId
为org.springframework.boot
。guava
也同理artifactId
:制品ID,可以理解为项目名。如spring-core
、spring-context
、spring-bean
等version
:该artifact
的版本
以上元素都是POM
中必须存在的。(在后续将要学习的继承关系中,有些元素可以省略,因为他们从父模块中继承)
其中groupId
、artifactId
以及version
这三个值组合在一起就构成了该项目或模块的全限定名,采用<groupId>:<artifactId>:<version>
的格式来表示,Maven
可以根据全限定名来找寻我们想要的jar
包等。
比如之前我们创建的简单Maven
demo中自动创建的POM
如下
我们将不需要的配置删掉,只留下最低配置
这个POM
描述了该项目的信息
首先是一个根标签<project>
;接下来值是固定4.0.0
的<modelVersion>
标签;<groupId>
表明该项目所属的机构/个人以及group
为org.example
;<artifactId>
标签说明了该项目的名称;<version>
表明了该项目的版本。所以该artifact
的全限定名为org.example:maven-demo:1.0-SNAPSHOT
2.2 packaging
我们的程序编写完之后,并不能像我们开发一样在IDEA
中运行,需要将他们打包成指定的制品。比如可能给其他人在项目里直接引用的jar
包,或是可以在Tomcat
中运行的web项目war
包。这时候就需要在POM
中定义packaging
元素来告诉Maven
我们想要什么。
<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">
...
<packaging>war</packaging>
...
</project>
上述例子中就是通知Maven
我们要项目打包成war
包。
2.2.1 默认值以及可选值
packaging
标签是可选标签,如果不进行声明,那么默认的打包方式为jar
。
目前可选值有pom
、jar
、maven-plugin
、ejb
、war
、ear
以及rar
。
2.2.2 示例
首先测试默认打包方式。
创建一个简单maven
项目pom-basic
,配置如下所示
待项目生成完毕之后,将pom.xm
精简为最小配置项,并且删掉src
下的test
文件夹。
在IDEA
右侧点击Maven
窗口,展开树结构菜单,进入Lifecycle
,右键package
,选择Run
或者Debug
,等待程序执行。
观察控制台输出,Maven
在指定的target
文件夹下将程序打包成了jar
包。
接下来测试打包成指定的方式
我们在pom.xml
中配置packaging
标签,指定打包方式
之后再点击右侧的Maven
窗口右键点击package
,观察控制台输出
可以看到Maven
已经将项目打包成我们想要的方式了。
2.3 POM
关系
Maven
的一个强大方面就是处理项目之间的关系:包括依赖关系(dependency
)、继承关系(inheritance
)以及聚合关系(aggregation
)。
2.3.1 依赖关系denpendency
POM
的基石就是依赖,大多数的项目都必须要使用第三方的jar
才能够运行,比如每个项目都在用的spring
框架,那么就需要依赖spring
的jar
。之前的方法是我们需要自己去下载这些jar
,问题就是这种做法非常麻烦,而且如果jar
的版本也会非常乱。
Maven
会帮助我们去管理这些jar
,包括下载所需要的jar
以及这些jar
依赖的jar
。
依赖关系的定义结构如下
<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>
<classifier>jdk8</classifier>
<optional>true</optional>
</dependency>
...
</dependencies>
...
</project>
所有依赖的根节点
每一个依赖用一组<dependency>
来定义。
使用权限定名,即groupId:artifactId:version
坐标来指定具体的依赖以及其版本。
Maven
会从中央仓库
中下载这些jar
以及这些jar
依赖的jar
到我们的本地仓库
,下载的完整路径见本地仓库
章节。
译为分类。可以是任意字符,该标签存在的意义是同一个Maven
坐标下还可以再细分小“版本”,或还有不同的制品,如json-lib
,它的每个版本下分为不同的jdk版本,如下所示
坐标都为net.sf.json-lib:json-lib:2.4
,但是却分为jdk13版本、jdk15版本,而每个版本下还分javadoc版本和sources版本。可以看出classfier
是附在version
之后的,那么坐标就变为groupId:artifactId:version:classfier
,jar
的名称也变为了artifactId-version-classfier.jar
了。上述例子中,如果我们要使用jdk13版本,那么应该按照如下方式定义dependency
<dependency>
<groupId>net.sf.json-lib</groupId>
<artifactId>json-lib</artifactId>
<version>2.4</version>
<classfier>jdk13</classfier>
</dependency>
type
选择依赖的类型,默认为jar
,通常为文件或依赖的扩展名。但是也有例外,如test-jar
、ejb-client
,这些类型的扩展名就与type
不同,官网给出了区别与联系Default Artifact Handlers Reference。
比如一个dependency
下既有jar
类型还有war
类型,那么就需要指定type
来选择我们想要的依赖
scope
了解scope
之前,先要了解依赖传递,可以看以下另一篇文章 // TODO
该依赖的生效范围,一共有六种scope
compile
(默认):在所有classpath下都可以可用,并且依赖关系会传播到依赖的项目中provided
:希望JDK或其他容器在运行时提供,只在编译以及测试的classpath下可用,没有传播性runtime
:表明编译期间不需要该依赖,但是运行时需要。在运行以及测试classpath下可用,编译classpath下不可用。test
:表明项目中并不会依赖次dependency
,只在测试classpath中生效,也就是在测试模块中会使用到,没有传播性system
:
2.3.1.1 中央仓库
2.3.1.2 本地仓库
我们之前层在Maven
的配置文件setting.xml
中添加了本地仓库地址,我们来观察一下本地仓库。
不难发现,Maven
将jar
下载到了它在Maven
中的坐标的相对路径文件夹。
上面的例子中,文件夹为org/springframework/boot/spring-boot-starter/2.5.2/spring-boot-starter-2.5.2.jar
而spring-boot-starter
的坐标为
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>2.5.2</version>
</dependency>
我们可以总结出a