Maven pom 继承聚合

1.1.0 简介

 

         对于一个pom.xml来讲有几个元素是必须定义的,一个是project根元素,而后就是它里面的modelVersion、groupId、artifactId和version。由上面的超级pom.xml的内容咱们能够看到pom.xml中没有groupId、artifactId和version的定义,因此咱们在创建本身的pom.xml的时候就须要定义这三个元素。和java里面的继承相似,子pom.xml会彻底继承父pom.xml中全部的元素,并且对于相同的元素,通常子pom.xml中的会覆盖父pom.xml中的元素,可是有几个特殊的元素它们会进行合并而不是覆盖。这些特殊的元素是: dependencies,developers, contributors, plugin列表(包括plugin下面的reports), resourcesjava

 

1.1.1继承

1.1.1.1 被继承项目与继承项目是父子目录关系apache

       如今假设咱们有一个项目projectA,它的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/maven-v4_0_0.xsd">  
  <modelVersion>4.0.0</modelVersion>  
  <groupId>com.tiantian.mavenTest</groupId>  
  <artifactId>projectA</artifactId>  
  <packaging>jar</packaging>  
  <version>1.0-SNAPSHOT</version>  
</project>

       而后咱们有另外一个项目projectB,并且projectB是跟projectA的pom.xml文件处于同一个目录下,这时候若是projectB须要继承自projectA的话咱们能够这样定义projectB的pom.xml文件。maven

<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/maven-v4_0_0.xsd">  
  <parent>  
    <groupId>com.tiantian.mavenTest</groupId>  
    <artifactId>projectA</artifactId>  
    <version>1.0-SNAPSHOT</version>  
  </parent>  
  <modelVersion>4.0.0</modelVersion>  
  <groupId>com.tiantian.mavenTest</groupId>  
  <artifactId>projectB</artifactId>  
  <packaging>jar</packaging>  
  <version>1.0-SNAPSHOT</version>  
</project>

由projectB的pom.xml文件的定义咱们能够知道,当须要继承指定的一个Maven项目时,咱们须要在本身的pom.xml中定义一个parent元素,在这个元素中指明须要继承项目的groupId、artifactId和version。ui

1.1.1.2 被继承项目与继承项目的目录结构不是父子关系spa

       当被继承项目与继承项目的目录结构不是父子关系的时候,咱们再利用上面的配置是不能实现Maven项目的继承关系的,这个时候咱们就须要在子项目的pom.xml文件定义中的parent元素下再加上一个relativePath元素的定义,用以描述父项目的pom.xml文件相对于子项目的pom.xml文件的位置。插件

       假设咱们如今仍是有上面两个项目,projectA和projectB,projectB仍是继承自projectA,可是如今projectB不在projectA的子目录中,而是与projectA处于同一目录中。这个时候projectA和projectB的目录结构以下:设计

       ------projectAcode

              ------pom.xmlxml

       ------projectB

              ------pom.xml

       这个时候咱们能够看出projectA的pom.xml相对于projectB的pom.xml的位置是“../projectA/pom.xml”,因此这个时候projectB的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/maven-v4_0_0.xsd">  
  <parent>  
    <groupId>com.tiantian.mavenTest</groupId>  
    <artifactId>projectA</artifactId>  
    <version>1.0-SNAPSHOT</version>  
       <relativePath>../projectA/pom.xml</relativePath>  
  </parent>  
  <modelVersion>4.0.0</modelVersion>  
  <groupId>com.tiantian.mavenTest</groupId>  
  <artifactId>projectB</artifactId>  
  <packaging>jar</packaging>  
  <version>1.0-SNAPSHOT</version>  
</project>

 

1.2.2聚合

       对于聚合这个概念搞java的人应该都不会陌生。先来讲说我对聚合和被聚合的理解,好比说若是projectA聚合到projectB,那么咱们就能够说projectA是projectB的子模块, projectB是被聚合项目,也能够相似于继承那样称为父项目。对于聚合而言,这个主体应该是被聚合的项目。因此,咱们须要在被聚合的项目中定义它的子模块,而不是像继承那样在子项目中定义父项目。具体作法是:

1)  修改被聚合项目的pom.xml中的packaging元素的值为pom

2)  在被聚合项目的pom.xml中的modules元素下指定它的子模块项目

对于聚合而言,当咱们在被聚合的项目上使用Maven命令时,实际上这些命令都会在它的子模块项目上使用。这就是Maven中聚合的一个很是重要的做用。假设这样一种状况,你同时须要打包或者编译projectA、projectB、projectC和projectD,按照正常的逻辑咱们一个一个项目去使用mvn compile或mvn package进行编译和打包,对于使用Maven而言,你仍是这样使用的话是很是麻烦的。由于Maven给咱们提供了聚合的功能。咱们只须要再定义一个超级项目,而后在超级项目的pom.xml中定义这个几个项目都是聚合到这个超级项目的。以后咱们只须要对这个超级项目进行mvn compile,它就会把那些子模块项目都进行编译。

1.2.2.1 被聚合项目和子模块项目在目录结构上是父子关系

还拿上面定义的projectA和projectB来举例子,如今假设咱们须要把projectB聚合到projectA中。projectA和projectB的目录结构以下所示:

------projectA

       ------projectB

              -----pom.xml

       ------pom.xml

这个时候projectA的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>  
  <groupId>com.tiantian.mavenTest</groupId>  
  <artifactId>projectA</artifactId>  
  <version>1.0-SNAPSHOT</version>  
  <packaging>pom</packaging>  
  <modules>  
       <module>projectB</module>  
  </modules>  
</project>

由上面的定义咱们能够看到被聚合的项目的packaging类型应该为pom,并且一个项目能够有多个子模块项目。对于聚合这种状况,咱们使用子模块项目的artifactId来做为module的值,表示子模块项目相对于被聚合项目的地址,在上面的示例中就表示子模块projectB是处在被聚合项目的子目录下,即与被聚合项目的pom.xml处于同一目录。这里使用的module值是子模块projectB对应的目录名projectB,而不是子模块对应的artifactId。这个时候当咱们对projectA进行mvn package命令时,实际上Maven也会对projectB进行打包。

1.2.2.2被聚合项目与子模块项目在目录结构上不是父子关系

那么当被聚合项目与子模块项目在目录结构上不是父子关系的时候,咱们应该怎么来进行聚合呢?仍是像继承那样使用relativePath元素吗?答案是非也,具体作法是在module元素中指定以相对路径的方式指定子模块。咱们来看下面一个例子。

继续使用上面的projectA和projectB,仍是须要把projectB聚合到projectA,可是projectA和projectB的目录结构再也不是父子关系,而是以下所示的这种关系:

------projectA

       ------pom.xml

------projectB

       ------pom.xml

这个时候projectA的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>  
   
  <groupId>com.tiantian.mavenTest</groupId>  
  <artifactId>projectA</artifactId>  
  <version>1.0-SNAPSHOT</version>  
  <packaging>pom</packaging>  
  <modules>  
       <module>../projectB</module>  
  </modules>  
</project>

注意看module的值是“../projectB”,咱们知道“..”是表明当前目录的上层目录,因此它表示子模块projectB是被聚合项目projectA的pom.xml文件所在目录(即projectA)的上层目录下面的子目录,即与projectA处于同一目录层次。注意,这里的projectB对应的是projectB这个项目的目录名称,而不是它的artifactId。

6.2.2.3聚合与继承同时进行

       假设有这样一种状况,有两个项目,projectA和projectB,如今咱们须要projectB继承projectA,同时须要把projectB聚合到projectA。而后projectA和projectB的目录结构以下:

       ------projectA

              ------pom.xml

       ------projectB

              ------pom.xml

       那么这个时候按照上面说的那样,projectA的pom.xml中须要定义它的packaging为pom,须要定义它的modules,因此projectA的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>  
  <groupId>com.tiantian.mavenTest</groupId>  
  <artifactId>projectA</artifactId>  
  <version>1.0-SNAPSHOT</version>  
  <packaging>pom</packaging>  
  <modules>  
       <module>../projectB</module>  
  </modules>  
</project>

     而projectB是继承自projectA的,因此咱们须要在projectB的pom.xml文件中新增一个parent元素,用以定义它继承的项目信息。因此projectB的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>  
  <parent>  
       <groupId>com.tiantian.mavenTest</groupId>  
       <artifactId>projectA</artifactId>  
       <version>1.0-SNAPSHOT</version>  
       <relativePath>../projectA/pom.xml</relativePath>  
  </parent>  
  <groupId>com.tiantian.mavenTest</groupId>  
  <artifactId>projectB</artifactId>  
  <version>1.0-SNAPSHOT</version>  
  <packaging>jar</packaging>  
</project>

 

        章节小结:其实说白了,聚合和继承是很是简单的,聚合的目的是实现一键build的功能,即A进行build的时候,下面聚合了的b,c,d都会进行build构建,而继承则是父pom对插件或者依赖jar进行了表述,使得子孙能够继承这样的规范和依赖,不过在继承中,也有须要注意甚至是才坑的地方,下面咱们给出实例。特别要注意在继承关系中,并非全部的依赖和插件都会继承,必定要区别开dependency标签是默认都继承,而dependencyManagement标签下的依赖或者pluginsManagement下的插件不是默认继承,而是须要声明,没有覆盖的内容就采用父pom中的内容,可是必定要声明。

 

Maven之——依赖与插件管理

并非父POM中配置的全部依赖在不一样的子类中都能用到、或者用到了可是不是统一版本、为解决这个、在父POM标签中定义依赖信息、在子POM中加入依赖的引入。具体细节以下:在父POM中配置项目中使用到的依赖、可是再也不是dependency标签中配置、由于此标签能够自动被继承、使用dependencyManagement标签、此标签中定义的dependency不会被子POM自动引入、必须在子类中使用dependency声明。可能有些时候会以为直接在子POM中引用依赖不就好了?一个是统一管理、另外一个是简化配置后面有提到。依赖管理两部实现:

a)在父POM中配置须要引入的依赖管理——scattered-items中的pom.xml:

<properties>
    <junit.version>4.1</junit.version>
  </properties>

  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>${junit.version}</version>
        <scope>test</scope>
      </dependency>
    </dependencies>
  </dependencyManagement>

上面使用了properties标签来定义全局变量、跟Java中定义变量意义项目、提取重复值。

b)在子POM中配置依赖——items-thkinjava中的pom.xml:

<dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
        </dependency>
</dependencies>

子POM中关于junit的依赖的引入只需配置groupId和artifactId就能够了、版本和scope都不用指定。

注意:关键的地方是在父POM中的dependencyManagement标签中配置的依赖是不会主动引入到子项目中的、也就是说虽然在父POM中的dependencyManagement定义了junit的依赖、假如子类中没有关于junit的<dependency>、那么子类就没有junit依赖的引入、而且假如子项目不想使用4.1版本的junit、还能够指定本身想要使用的junit版本、这样就彻底覆盖了父POM中关于junit的定义、也就是说父POM中的junit定义与他无关。这样的灵活性已经够知足咱们平常需求了。

建议依赖都放在父POM中的dependencyManagement、一个是减小配置、二个是方便管理、好比版本冲突就是很常见的问题。经过dependencyManagement+变量的方式统一管理、更安全高效。

依赖范围有一种是import、是只有在dependencyManagement元素下才有效果的、使用该范围的依赖一般指向一个POM、做用是将目标POM中的dependencyManagement配置导入并合并到当前POM的dependencyManagement元素中。例如想在另一个模块中使用上面配置的dependencyManagement配置、除了复制继承以外还可使用import范围依赖将这已配置导入:

<dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>org.andy.items</groupId>
        <artifactId>scattered-items</artifactId>
        <type>pom</type>
        <version>1.0-SNAPSHOT</version>
        <scope>import</scope>
      </dependency>
      <dependency>
        <groupId>othergi</groupId>
        <artifactId>otherai</artifactId>
        <version>${other.version}</version>
      </dependency>
    </dependencies>
  </dependencyManagement>

三、插件管理

插件管理与依赖管理原理同样、不一样的是定义的元素标签不同、插件管理标签是build标签的子标签pluginManagement、在父POM中定义、子POM引用。如前面有个生成源码包的插件、使用插件管理的配置过程以下:

a)父POM——scattered-items中的pom.xml:

<build>
    <pluginManagement>
      <plugins>
        <plugin>
          <groupId>org.apache.maven.plugins</groupId>
          <artifactId>maven-source-plugin</artifactId>
          <version>${sources.plugin.verion}</version>
          <executions>
            <execution>
              <id>attach-sources</id>
              <phase>verify</phase>
              <goals>
                <goal>jar-no-fork</goal>
              </goals>
            </execution>
          </executions>
        </plugin>
        <plugin>
          <groupId>org.apache.maven.plugins</groupId>
          <artifactId>maven-compiler-plugin</artifactId>
          <version>3.1</version>
          <configuration>
            <source>1.7</source>
            <target>1.7</target>
          </configuration>
        </plugin>
      </plugins>
    </pluginManagement>
  </build>

b)子POM——items-thkinjava中的pom.xml:

<build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-source-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

注意的东西与依赖管理相似、只是换成了插件管理。

四、约定优于配置

标准的重要性已经不用过多强调、ConventionOver Configuration是maven最核心的设计理念之一。

任何一个maven项目都隐式的继承了超级POM、有点相似与Java全部的类都继承Object类、所以、大量超级POM的配置都会被全部maven项目继承、这些配置也就成为了maven所提倡的约定。

超级POM位置:$M2_HOME/lib/maven-model-builder-x.x.x.jar中的org/apache/maven/model/pom-4.0.0.xml路径下。

相关文章
相关标签/搜索