Maven pom配置说明

pom介绍

POM( Project Object Model,项目对象模型 ) 是 Maven 工程的基本工作单元,是一个XML文件,包含了项目的基本信息,用于描述项目如何构建,声明项目依赖,等等。

执行任务或目标时,Maven 会在当前目录中查找 POM。它读取 POM,获取所需的配置信息,然后执行目标。

POM 中可以指定以下配置:项目依赖、插件、执行目标、项目构建 profile、项目版本、项目开发者列表、相关邮件列表信息

pom.xml文件基本结构

<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
    http://maven.apache.org/xsd/maven-4.0.0.xsd">
 
    <!-- 模型版本 -->
    <modelVersion>4.0.0</modelVersion>
    <!-- 公司或者组织的唯一标志,并且配置时生成的路径也是由此生成, 如com.companyname.project-group,maven会将该项目打成的jar包放本地路径:/com/companyname/project-group -->
    <groupId>com.companyname.project-group</groupId>

    <!-- 项目的唯一ID,一个groupId下面可能多个项目,就是靠artifactId来区分的 -->
    <artifactId>project</artifactId>

    <!-- 版本号 -->
    <version>1.0</version>
</project>

所有 POM 文件都需要 project 元素和三个必需字段:groupId,artifactId,version。

节点 描述
project 工程的根标签。
modelVersion 模型版本需要设置为 4.0。
groupId 这是工程组的标识。它在一个组织或者项目中通常是唯一的。例如,一个银行组织 com.companyname.project-group 拥有所有的和银行相关的项目。
artifactId 这是工程的标识。它通常是工程的名称。例如,消费者银行。groupId 和 artifactId 一起定义了 artifact 在仓库中的位置。
version 这是工程的版本号。在 artifact 的仓库中,它用来区分不同的版本。例如:com.company.bank:consumer-banking:1.0

pom.xml的结构说明

pom.xml的基础结构

<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
                      http://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>

groupId、artifactId、version三个字段上面已经提到不在过多介绍。

pom父标记集成

这里的继承概念与java中类的继承概念类似,子pom拥有父pom的所有配置, 可以通过自定义的方式覆盖/复写父pom中已经存在的配置。

举例

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.1.1.RELEASE</version>
</parent>

另一种方式

<dependencyManagement>
    <dependencies>
        <dependency>
            <!-- Import dependency management from Spring Boot -->
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-dependencies</artifactId>
            <version>2.1.1.RELEASE</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

dependencies标签,依赖包维护

举例

<dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.12</version>
      <type>jar</type>
      <scope>test</scope>
      <optional>true</optional>
    </dependency>
</dependencies>

dependencies标签下声明了当前项目所使用的依赖构件。

需要注意的是,这里声明的文件必须能够在maven仓库中找到, maven默认使用中央仓库,中央仓库中包括了所有常用的开源jar包, 但对于一些闭源的三方jar包,就无法在中央仓库中找到。
因此,公司一般都会有自己的私有仓库,我们需要修改maven的settings.xml文件, 使maven使用私服处理依赖和发布。

scope标签

该标签定义了该包在哪些阶段会被放到classpath中,另外还定义了依赖的可传递性。其聚会范围如下:

classpath即类、类库加载路径,在我们的依赖中,大多数依赖会在编译、测试、运行都用到, 但也有一些依赖可能只有在编译、测试阶段运到(比如测试相关的包),还有部分包可能在编译、测试时需要, 但实际发布时不需要(比如jdk相关的包)。

含义 是否会将该依赖向下传递
compile 该值是默认值。该依赖在所有阶段的都会放入classpath中,是最常用的值。
provided 只有在编译和测试时放入classpath中,实际打包时忽略该包
runtime 编译时不需要,只在测试和打包时需要
test 只在对测试代码做编译和执行时需要
system 手动指定所依赖包的本地存在路径 只传递本身
  • compile是最常用的,一般项目引入的包在编译、测试、发布阶段都会用到。

  • provided一般用于基础包,在基础包的开发过程中会依赖一些三方包, 但可能不想为使用者带来依赖冲突的负担,此时可以使用该范围,由使用者自行决定该三方包的版本 (当然需要是兼容的版本);另一种不推荐的使用方式是将该依赖作为可选依赖向下传递, 举一个例子:我们开发了一个基础工具类包,里面含有许多工具,像poi工具、时间转换工具、中文数字工具, 另外里面还包含了TapConfigUtil用来获取配置, 此时我们注意到配置中心的集成是以springboot为基础的, 而我们想让该工具包也可以被其他类型的项目使用, 这种情况下我们可以给commons-aap-appconfig包加上provided范围。 如果某个使用者只不需要使用TapConfigUtil,那么他就不需要引入commons-aap-appconfig包。 (事实上commons-aap-appconfig包里引入spring相关的依赖里使用了provided范围)

  • runtime很少用到,一般情况下使用compile就可以了, 使用runtime甚至可能给IDE带来一些问题

  • test用在测试相关的包上,测试代码的安全性会更低(毕竟没人会写测试代码来测试测试代码 ——对外发布的测试工具除外),使用test标记测试相关的包,可以避免被其他开发人员错误的使用。

  • system需要配置systemPath标签使用,用来指定使用仓库中没有的包。 与其相比,上传私服是一种更好的方式,因为system标记的包,并不会将其依赖的包传递给使用者, 这意味着你需要自己处理好依赖关系。

exclusions标签

dependency标签下还存在exclusions标签,我们在前面讲到了依赖传递可能带来的依赖冲突问题, exclusions标签就是排除掉不想被传递过来的依赖。

这里需要注意的是,A->B->C时,如果你在引入依赖A的时候,将B排除,那么C也将被排除, 除非有其他地方也引入了C(有点像对“树”进行操作,排除进相当于直接剪掉了一个“子树”)

<exclusions>
    <exclusion>
        <groupId>org.objenesis</groupId>
        <artifactId>objenesis</artifactId>
    </exclusion>
</exclusions>

exclusion下只有groupId与artifactId两个标签,因为只不可能同时依赖一个包的不同版本。