一、什么是POM?
POM是Project Object Model的缩写,是Maven工作的基础单元;POM.xml是一个包含关于Maven项目信息和配置详情的XML文件,是用来构建(build)项目的;它包含大多数项目的默认值;例如,构建项目的【target】文件夹;例如,资源文件夹——【src/main/java】;例如测试资源文件夹——【src/test/java】等等;当执行一个任务或目标,Maven会在当前文件夹内找POM文件。然后读取POM里的信息,获取需要的配置信息,然后执行目标;
一些POM里的特殊配置是项目的依赖(Project Dependencies);这里的依赖指的是项目依赖的jar包;还有一些事插件或可执行的目标,构建配置等;其他的信息例如项目版本,描述,开发者,邮件列表等都可以被特别定义;
二、超级POM
超级POM是Maven默认的POM,所有的POM文件们都继承了这个超级POM,除非明确定义了不继承;超级POM文件被你创建的其他POM文件们继承,目前最新的超级POM文件是3.5.4;(你可以理解为所有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文件要求有一下5个部分:
- 项目根目录;
- 模块版本-必须被设置成4.0.0;
- 组别ID-项目的组别的ID;
- 产品ID-项目产品的ID;
- 版本-在特定组别下的项目产品的版本;
下面是一个例子
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.mycompany.app</groupId>
<artifactId>my-app</artifactId>
<version>1</version>
</project>
一个POM文件会要求配置你的groupId,artifactId和版本号;这3个值可以完整的定义一个产品;以<groupId>:<artifactId>:<version>
的形式;按照上面的例子,上面项目完整的产品名是:
com.mycompany.app:my-app:1
同样的,第一节提到的,如果没有明确定义配置信息,Maven会使用默认值。其中一种默认值是打包类型(packaging type);每个Maven 项目都有一个打包类型;如果POM里没有明确定义,那么,默认的打包类型会是jar包;
此外,你可以看到,最简单的POM文件里,仓库(repositories)是没有明确配置的。如果你使用最简单的POM文件来构建项目,他会继承超级POM的仓库配置;因此,当Maven看到最简单POM文件里的依赖,他会直接去中央仓库去下载(http://repo.maven.apache.org/maven2
),这是所有POM文件的超级POM配置仓库;
四、项目继承
POM文件里元素的会被合并如下:
- 依赖jar包
- 开发者和贡献者
- 插件列表(包括报告)
- 匹配到id的插件;
- 插件配置
- 资源
超级POM文件是一个项目继承的经典例子,但是,如果你想通过特定的POM中父类元素引入你自己的父类POM文件,建议看看以下案例演示:
4.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文件如下:(即,我们再子类的POM文件里修改,添加父类的信息)
<project>
<parent>
<groupId>com.mycompany.app</groupId>
<artifactId>my-app</artifactId>
<version>1</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>com.mycompany.app</groupId>
<artifactId>my-module</artifactId>
<version>1</version>
</project>
注意,我们添加了一个标签组节,这个组节允许我们在POM文件里特别定义产品的父类信息;我们通过定义其父类POM的【全限定产品名】(fully qualified artifact name);我们的模块就可以继承其父类POM了;
除此之外,如果我们想让我们模块的groupID或version和其父类一样,我们可以移除子类模块POM文件中的groupId或version;
<project>
<parent>
<groupId>com.mycompany.app</groupId>
<artifactId>my-app</artifactId>
<version>1</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>my-module</artifactId>
</project>
4.2、案例二
然而,上述案例一的那种情况,必须是父项目已经在我们本地仓库安装(installed)或者被特别定义了结构pom.xml
父pom.xml是一个比你当前模块的pom.xml高级的文件夹;
但是,如果父项目没有被安装或者文件夹结构是如下的例子:
.
|-- my-module
| `-- pom.xml
`-- parent
`-- pom.xml
解决方案:
添加文件夹结构地址(或任意其他目录地址),我们可以添加关联路径<relativePath>
原来到父组节里
<project>
<parent>
<groupId>com.mycompany.app</groupId>
<artifactId>my-app</artifactId>
<version>1</version>
<relativePath>../parent/pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>my-module</artifactId>
</project>
作为名字的建议,模块的相对路径的pom.xml是父pom.xml
五、项目聚合
项目的聚类类似于项目的继承,但是不是在模块的父pom文件,而是在父POM里;通过这样的操作,父项目可以知道他的子模块,并且,如果Mavne命令是在父项目里调用的,Maven命令可以在父模块中执行;为了做模块聚合,你必须做如下操作:
1. 修改父POMs打包的值为pom(而不是jar)
2. 特别定义父类的POM中子模块的目录
5.1、案例三
下面给定了一个原始的产品的POMs和目录结构
com.mycompany.app:my-app:1's POM
的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's POM
的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
模块的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-app:1
模块,打包的组节和模块的组节被添加进去了;为了打包,他的值被修改为了“pom”,并且模块的组节,我们有元素:<module>my-module</module>
模块的值是com.mycompany.app:my-app:1
相对 com.mycompany.app:my-module:1's POM
的相对路径;(我们特别用了模块的产品的模块目录名);
现在,无论Maven命令处理 com.mycompany.app:my-app:1
,相同的maven命令会同时在 com.mycompany.app:my-module:1
里执行;此外,一些命令(目标特别定义)的会被项目特殊处理;
5.2、案例四
但是,如果我们按照下面的来修改目录呢?
.
|-- 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工程继承其父类项目,并且配置必须与其一致;
并且,如果你有一个项目组,你要构建或者同时处理,你可以创建一个父工程,并且让父工程来定义它的子类;这样,你紧紧需要构建父项目,其他的子项目就会自动执行,不需要你操心了;
但是,同样的,你如果既有项目继承又有项目依赖;注意,你可以特定一个父项目,同时,定义这个父项目的子项目;你必须遵循下面3条规则:
1. 在父POM定义其所有的子项目POM;
2. 修改父项目的POMs的打包方式为pom
3. 特别定义父POM的目录给子项目;
6.1、案例5
给定了如下原始的POMs的产品
com.mycompany.app:my-app:1’s 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’s 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
解决方案
为了两个项目都继承和聚合,你仅仅需要遵从上述3条内容;
com.mycompany.app:my-app:1’s 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’s POM
<project>
<parent>
<groupId>com.mycompany.app</groupId>
<artifactId>my-app</artifactId>
<version>1</version>
<relativePath>../parent/pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>my-module</artifactId>
</project>
注意:配置文件的继承相同的继承策略;
七、项目插值与变量
Maven鼓励的一个经验就是【不要重复】;然而,如果你需要使用在不同的地方多次使用相同的变量;为了帮助变量是唯一定义的,Maven允许你在POM文件里预定义自己的变量;
例如,为了得到 project.version
变量,你可以定义如下:
<version>${project.version}</version>
注意一个事实,变量在被继承之后处理;这意味着,如果一份父项目要使用一个变量,如果这个变量定义在子项目中,而不是父项目中,则子项目中的变量将会被最终使用;