在上一节当中,我们使用 Maven 创建了我们的第一个项目,今天我们来介绍一下 Maven 中重要的概念 POM 模型。
1. POM 模型
1.1 什么是 POM?
POM(项目对象模型)是 Maven 最基本,也是非常重要的一个概念。通常情况下,我们可以看到 POM 的表现形式是 pom.xml,在这个 XML 文件中定义着关于我们工程的方方面面,当我们想要通过 Maven 命令来进行操作的时候,例如:编译,打包等等,Maven 都会从 pom.xml 文件中来读取工程相关的信息。
1.2 查看项目结构
我们在 cmd 中打开项目根目录,执行 tree /f 命令。可以看到如下图的项目结构:
- 每个项目都有一个 pom.xml 文件,该文件中定义本项目的对象模型,描述本项目,配置插件,声明依赖;
- 对于简单的 Maven 项目,src/main 目录放置项目的源码和资源文件,一般情况下,源码放置在 Java 目录下,App.java 就是 Maven Archtype 插件生成的一个简单类,classpath 资源文件放置在resources 目录下。
- src/test 目录下放置我们的测试用例,与 main 目录类似,src/test/java 目录下放置我们的测试类源码,AppTest.java 则是 Maven Archtype 插件生成的一个简单测试类,src/test/resources 放置测试用到的 classpath 资源文件。
注: 这里 Maven 只是帮我们创建了一个简单的 Maven 项目,其中 resources 目录则需要手动创建。
1.2 查看项目 pom.xml 文件
我们打开项目中的 pom.xml 文件,如下图:
现在看到的这个 pom.xml 是 Maven 项目中最基础的 POM,后面随着项目的慢慢的进行,这个 pom.xml会变得更加复杂,我们可以向其中添加更多的依赖,也可以在里面配置我们需要的插件。
从头开始看:groupId,artifactId,packaging,version 几个元素是 Maven 的坐标,用来唯一标识一个项目。
接下来是 name,url 这两个元素则是用来描述信息,给人更好的可读性。
最后是 dependencies,这里 Maven 默认依赖了 3.8.1 版本的 junit,其中 scope 用来标记该依赖的范围为 test。
1.3 Maven 的坐标
接下来我们就重点介绍一下 Maven 的坐标(Coordinates)。
- groupId:groupId 为我们组织的逆向域名,这里的组织可以是公司,团体,小组等等。例如Apache 基金会的项目都是以 org.apache 来作为 groupId 的;
- artifactId:该组织下,项目的唯一标识;
- packaging:项目类型,描述的是项目在打包之后的输出结果,常见的 jar 类型的输出结果是一个jar 包,war 类型则输入 war 包,一般 Web 项目的打包方式为 war。
version:项目的版本号,用来标记本项目的某一特定版本。SNAPSHOT 则是用来标记项目过程中的快照版本,该版本类型表明本项目不是稳定版本,常见的还有 RELEASE,则表示该版本为本项目的稳定版本。
2. 超级 POM
在我们这个项目的 pom.xml 文件中,只有短短的几行信息,但是这就全部吗?其实不然。
在 Maven 的世界中,存在着一个超级 POM(super POM),所有通过 Maven 创建的项目,其 pom.xml 文件都会继承这个超级 POM。所以在默认情况下,使用 Maven 创建出来的项目基本上都是很类似的。
那么这个超级 POM 在哪呢?长什么样呢?2.1 超级 POM 路径位置
如下图,先找到指定的 jar 包,路径:.\apache-maven-3.6.3\lib\maven-model-builder-3.6.3.jar:

然后我们可以使用解压工具查看该 jar 包,找到对应的 pom.xml。
具体路径:org\apache\maven\model\pom-4.0.0.xml。2.2 查看超级 POM 结构
<project><modelVersion>4.0.0</modelVersion><repositories><repository><id>central</id><name>Central Repository</name><url>https://repo.maven.apache.org/maven2</url><layout>default</layout><snapshots><enabled>false</enabled></snapshots></repository></repositories><pluginRepositories><pluginRepository><id>central</id><name>Central Repository</name><url>https://repo.maven.apache.org/maven2</url><layout>default</layout><snapshots><enabled>false</enabled></snapshots><releases><updatePolicy>never</updatePolicy></releases></pluginRepository></pluginRepositories><build><directory>${project.basedir}/target</directory><outputDirectory>${project.build.directory}/classes</outputDirectory><finalName>${project.artifactId}-${project.version}</finalName><testOutputDirectory>${project.build.directory}/test-classes</testOutputDirectory><sourceDirectory>${project.basedir}/src/main/java</sourceDirectory><scriptSourceDirectory>${project.basedir}/src/main/scripts</scriptSourceDirectory><testSourceDirectory>${project.basedir}/src/test/java</testSourceDirectory><resources><resource><directory>${project.basedir}/src/main/resources</directory></resource></resources><testResources><testResource><directory>${project.basedir}/src/test/resources</directory></testResource></testResources><pluginManagement><!-- NOTE: These plugins will be removed from future versions of the super POM --><!-- They are kept for the moment as they are very unlikely to conflict with lifecycle mappings (MNG-4453) --><plugins><plugin><artifactId>maven-antrun-plugin</artifactId><version>1.3</version></plugin><plugin><artifactId>maven-assembly-plugin</artifactId><version>2.2-beta-5</version></plugin><plugin><artifactId>maven-dependency-plugin</artifactId><version>2.8</version></plugin><plugin><artifactId>maven-release-plugin</artifactId><version>2.5.3</version></plugin></plugins></pluginManagement></build><reporting><outputDirectory>${project.build.directory}/site</outputDirectory></reporting><profiles><!-- NOTE: The release profile will be removed from future versions of the super POM --><profile><id>release-profile</id><activation><property><name>performRelease</name><value>true</value></property></activation><build><plugins><plugin><inherited>true</inherited><artifactId>maven-source-plugin</artifactId><executions><execution><id>attach-sources</id><goals><goal>jar-no-fork</goal></goals></execution></executions></plugin><plugin><inherited>true</inherited><artifactId>maven-javadoc-plugin</artifactId><executions><execution><id>attach-javadocs</id><goals><goal>jar</goal></goals></execution></executions></plugin><plugin><inherited>true</inherited><artifactId>maven-deploy-plugin</artifactId><configuration><updateReleaseInfo>true</updateReleaseInfo></configuration></plugin></plugins></build></profile></profiles></project>
对于我们的项目,我们称超级 POM 为父 POM,我们项目中的 POM 为子 POM,一般情况下如果父子 POM 中存在相同的元素或者节点,那么子 POM 会覆盖父 POM 的元素或者节点(有点类似 Java 中的 override),但是,也会有这么几个例外存在:
dependencies;
- developers 和 contributors;
- plugins;
- resources。
子 POM 在继承这些元素的时候,并不会直接覆盖,而是在其基础上继续追加。
3. 小结
本节中,我们介绍了 Maven 的 POM 模型,查看 Maven 工程的 pom.xml 文件,以及 pom.xml 文件中的坐标,最后我们还介绍了超级 POM,这样,我们就对 Maven 的 POM 模型有了一个基本的认识。
