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路徑下。

相關文章
相關標籤/搜索