Maven POM 模型
在上一节当中,我们使用 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 模型有了一个基本的认识。