POM(Project Object Model)是Maven的基本工作单元。它包含项目的信息,和Maven用来构建项目的配置细节。
很多配置都有默认值,比如源代码目录是src/main/java,测试源代码目录是src/test/java,构建目录是target等等。
执行任务或目标时,Maven在当前目录中查找POM。它读取POM,获取所需的配置信息,然后执行目标。
可以在POM中指定的配置有项目依赖项、可以执行的插件或目标、构建profiles等等。还可以指定其他信息,如项目版本、说明、开发人员、邮件列表等。
Super POM
即Maven的默认POM,包含很多默认配置。
所有POM都会继承Super POM,除非显示设置。所以Super POM中的配置都会被我们创建的POM继承过来,这就是默认配置。
下面是Maven 3.6.3的Super POM:
4.0.0centralCentral Repositoryhttps://repo.maven.apache.org/maven2defaultfalsecentralCentral Repositoryhttps://repo.maven.apache.org/maven2defaultfalsenever${project.basedir}/target${project.build.directory}/classes${project.artifactId}-${project.version}${project.build.directory}/test-classes${project.basedir}/src/main/java${project.basedir}/src/main/scripts${project.basedir}/src/test/java${project.basedir}/src/main/resources${project.basedir}/src/test/resources maven-antrun-plugin 1.3 maven-assembly-plugin 2.2-beta-5 maven-dependency-plugin 2.8 maven-release-plugin 2.5.3${project.build.directory}/siterelease-profileperformReleasetruetrue maven-source-plugin attach-sourcesjar-no-forktrue maven-javadoc-plugin attach-javadocsjartrue maven-deploy-plugin true
最小的POM
4.0.0com.mycompany.app my-app 1
一个POM必须配置groupId、artifactId、version,这三个值形成项目工件的全限定名,::,比如:com.mycompany.app:my-app:1
其他未配置但必需的,则会使用默认值。比如,每个Maven项目都会有一个packaging类型,如果没有配置,那么默认是jar。
又比如,如果没有配置repositories,那么会Maven会使用Super POM中配置的repositories,即依赖都从https://repo.maven.apache.org/maven2下载。
项目继承(Project Inheritance)
子POM会将父POM中的下列配置合并过来:
- dependencies
- developers and contributors
- plugin lists (including reports)
- plugin executions with matching ids
- plugin configuration
- resources
Super POM就是项目继承的一个例子。当然,我们也可以引入自己的父POM。
还是使用上面的项目 com.mycompany.app:my-app:1。
假设要开发另外一个项目 com.mycompany.app:my-module:1,它的POM是这样的:
4.0.0com.mycompany.app my-module 1
现在,我们要把项目com.mycompany.app:my-app:1转变为项目com.mycompany.app:my-module:1的父项目,只需要修改项目com.mycompany.app:my-module:1的POM即可:
4.0.0com.mycompany.app my-app 1com.mycompany.app my-module 1
这样,项目com.mycompany.app:my-module:1就可以继承父项目的所有配置了。
上面的元素的配置只适用于父项目已经安装在本地仓库或者将这两个项目的目录结构设计为:
如果父项目没有安装在本地仓库且两个项目的目录结构也不是上面那样,该怎么办?假设目录结构是这样的:
现在我们只需要在元素添加一个元素指定父项目的路径即可:
com.mycompany.app my-app 1../parent/pom.xml
项目聚合(Project Aggregation)
项目继承是在子项目中指定父项目。
而项目聚合则是在父项目中指定子项目。
项目继承是为了子项目能够继承父项目中的配置。
而项目聚合则是为了在为父项目执行Maven命令时,自动的为所有子项目执行相同的命令,有点类似于批量执行Maven命令。
假设有两个项目,原来的POM是这样的。
com.mycompany.app:my-app:1的POM:
4.0.0com.mycompany.app my-app 1
com.mycompany.app:my-module:1的POM:
4.0.0com.mycompany.app my-module 1
它们的目录结构是这样的:
现在要把my-module聚合到my-app中,我们只需要修改my-app的POM即可:
4.0.0com.mycompany.app my-app 1pommy-module
如果它们的目录结构变为:
那么只需这样修改即可:
../my-module
项目继承 vs 项目聚合
如果多个Maven项目有类似的配置,那么把类似的配置抽出来形成父项目,子项目只要继承父项目即可获得那些配置,减少了子项目中的重复配置。
如果有一组项目需要一起构建和处理,那么创建一个父项目把它们作为模块/子项目,只要构建父项目就会自动的构建所有的子项目,减少了子项目的逐个构建。
当然,我们可以同时使用这两种技术,那么就可以同时获得这两种好处。POM修改只需要三步:
- 为每个子POM指定父POM
- 将父POM的packaging的值配置为pom
- 在父POM中指定子项目/模块所在的目录。
变量
还是为了解决重复性的问题。有时候需要在多个位置使用同一个值,这时候就我们可以使用POM预定义的或者我们自定义的变量。
比如,我们可以这样访问 project.version 这个变量:
${project.version}
注意:变量是在继承之后处理的,所以,如果父项目使用变量,则其值最终可能是子项目中所定义的值。
变量有三类:
- POM本身的变量:只要是具有单个值的元素,都可作为变量,比如:${project.groupId}、${project.version}、${project.build.sourceDirectory},这些变量都是以 project. 开头的。
- 特殊的变量:
- project.basedir:当前项目所在的目录。
- project.baseUri :当前项目所在的目录,使用URI表示。
- maven.build.timestamp :构建开始的UTC时间戳。时间戳的格式可以自定义(格式的标准参考java.text.SimpleDateFormat):
... yyyy-MM-dd'T'HH:mm:ss'Z' ...
- 自己定义的属性:
... 3.0org.apache.maven maven-artifact ${mavenVersion}org.apache.maven maven-core ${mavenVersion} ...