Maven POM元素繼承


        為了減少重復代碼的編寫,我們需要創建POM的父子結構,然后在POM中申明一些配置供子POM繼承,以實現“一處申明,多處使用的”目的。以之前的模塊中的結構為基礎,在account-aggregator下創建一個account-parent的子目錄,然后在該子目錄下創建除account-aggregator模塊之外的模塊的父模塊。為此在該子目錄下創建一個pom.xml文件如下:

<?xml version="1.0" encoding="UTF-8"?>  
<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.juvenxu.mvnbook.account</groupId>  
        <artifactId>account-parent</artifactId>  
        <version>1.0.0-SNAPSHOT</version>  
        <packaging>pom</packaging>  
        <name>Account Parent</name>     
</project> 

        需要注意的是它的packaging的值必須為pom,這一點與模塊聚合一樣,作為負模塊的POM,其打包類型也必須為pom。由於父模塊只是為了消除配置的重復,因此也就不需要src/main/java等目錄了。

        有了父模塊就讓其他子模塊來繼承它,修改account-email的pom文件如下:

<?xml version="1.0" encoding="UTF-8"?>  
<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> 
        <parent>
            <groupId>com.juvenxu.mvnbook.account</groupId>  
            <artifactId>account-parent</artifactId>  
            <version>1.0.0-SNAPSHOT</version>  
            <relativePath>../account-parent/pom.xml</relativePath>  
        </parent> 
        <artifactId>account-email</artifactId> 
        <name>Account Email</name> 

        <dependencies>
                ......
        </dependencies>

        <build>
                <plugins>
                    ......
                </plugins>
        </build>

</project>

        parent下的子元素groupId、artifactId和version指定了父模塊的坐標,這三個元素是必須的。元素relativePath表示父模塊POM的相對路徑。當項目構建時,Maven會首先根據relativePath檢查父POM,如果找不到,再從本地倉庫查找。relativePath的默認值是../pom.xml,也就是說,Maven默認父POM在上一層目錄下。

        這個更新過的POM文件並沒為account-email設置artifactId和version,實際上這個子模塊隱式的從父模塊繼承了這兩個元素。如果子模塊中遇到與父模塊中不一樣的artifactId、version這個時候應該在子模塊顯示聲明。

        最后還要把父模塊加入到聚合模塊account-aggregator中如下:

<?xml version="1.0" encoding="UTF-8"?>  
<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.juvenxu.mvnbook.account</groupId>  
        <artifactId>account-aggregator</artifactId>  
        <version>1.0.0-SNAPSHOT</version>  
        <packaging>pom</packaging>  
        <name>Account Aggregator</name>  
        <modules>
             <module>account-parent</module>    
             <module>account-email</module>  
             <module>account-persist</module>  
        <modules>     
</project>    

此時的目錄結構是account-parent、account-email、account-persist在同一級目錄,account-aggregator為三個目錄的父目錄。

可繼承的POM元素如下:

  • groupId:項目組ID,項目坐標的核心元素
  • version:項目版本,項目坐標的核心因素
  • description:項目的描述信息
  • organization:項目的組織信息
  • inceptionYear:項目的創始年份
  • url:項目的URL地址
  • developers:項目的開發者信息
  • contributors:項目的貢獻者信息
  • distributionManagement:項目的部署配置
  • issueManagement:項目的缺陷跟蹤系統信息
  • ciManagement:項目的持續集成系統信息
  • scm:項目的版本控制系統西溪
  • malilingLists:項目的郵件列表信息
  • properties:自定義的Maven屬性
  • dependencies:項目的依賴配置
  • dependencyManagement:項目的依賴管理配置
  • repositories:項目的倉庫配置
  • build:包括項目的源碼目錄配置、輸出目錄配置、插件配置、插件管理配置等
  • reporting:包括項目的報告輸出目錄配置、報告插件配置等

  依賴管理

  因為dependencies元素也是可繼承的,因此我們可以把公共的jar放到父模塊account-parent中,比如org.springframework:spring-core:2.5.6在account-email,account-persist模塊中都會用到,因此可以將這個依賴配置放到父模塊中,兩個子模塊就能移除這些依賴從而簡化配置。

  上述做法是可行的,但是存在問題。因為所有的子模塊都會繼承以上父模塊的依賴項,不管子模塊是否真的需要此依賴項。這樣相當於子模塊失去了這些依賴項繼承的選擇權。假設后面加了模塊acount-util與springframework沒有半毛錢關系,讓他依賴spring的依賴項顯然是不合理的。

  為此Maven提供了dependencyManagement元素既能讓子模塊繼承到父模塊的依賴配置,又能保證子模塊依賴的使用靈活性。在dependencyManagement元素下的依賴聲明不會引入到實際的依賴,不過它能約束dependencies下的依賴使用。

<?xml version="1.0" encoding="UTF-8"?>  
<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.juvenxu.mvnbook.account</groupId>  
        <artifactId>account-parent</artifactId>  
        <version>1.0.0-SNAPSHOT</version>  
        <packaging>pom</packaging>  
        <name>Account Parent</name> 
        <properties>
                <springframework.version>2.5.6</springframework.version>
        </properties>

        <dependencyManagement>
                <dependencies>
                       <dependency>
                            <groupId>org.springframework </groupId>
                            <artifactId>spring-core</artifactId>
                            <version>${springframework.version}</version>
                       </dependency>

                       ......

                </dependencies>
        </dependencyManagement>
</project>     

  這里使用了dependencyManagement聲明的依賴既不會給account-parent引入依賴項,也不會給他的子模塊引入依賴,不過這段配置會被繼承。現在修改account-email的POM文件如下:

<?xml version="1.0" encoding="UTF-8"?>  
<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> 
        <parent>
            <groupId>com.juvenxu.mvnbook.account</groupId>  
            <artifactId>account-parent</artifactId>  
            <version>1.0.0-SNAPSHOT</version>  
            <relativePath>../account-parent/pom.xml</relativePath>  
        </parent> 
        <artifactId>account-email</artifactId> 
        <name>Account Email</name> 

        <dependencies>
                <dependency>
                    <groupId>org.springframework</groupId>
                    <artifactId>spring-core</artifactId>
                </dependency>
                
                ......
                
        </dependencies>

        <build>
                <plugins>
                    ......
                </plugins>
        </build>

</project>

  上面的配置較原來簡單了一些,只配置了groupId和artifactId,省去了version,如果父模塊配置了依賴的scope也是可以省略的。這些信息可以省略是因為account-email繼承了account-parent中的dependencyManagement配置,完整的依賴聲明已經包含在父POM中了,子模塊只需簡單的配置groupId和artifactId。

  使用這種以來管理機制雖然不能減少太多的配置項,但是經過別人實踐后強烈推薦的方法。如果子模塊不聲明依賴的使用,即使該依賴已經在父POM文件dependencyManagement中聲明了,也不會產生任何實際的效果。

 

插架管理

  Maven提供了dependencyManagement元素幫助管理依賴,類似的,Maven也提供了pluginManagement元素幫助管理插件。當子模塊POM中配置了plugin,並且groupId和artifactId與pluginManagement中的配置的插件匹配時,pluginManagement的配置才會真正影響實際插件的行為。

  父POM文件:

  <build>
  <pluginManagement>
  <plugins>
  <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-source-plugin</artifactId>
    <version>2.1.2</version>
    <executions>
      <execution>
        <id>attach-sources</id>
        <phase>verify</phase>
        <goals>
          <goal>jar-no-fork</goal>
        </goals>
      </execution>
    </executions>
  </plugin>
  </plugins>
  </pluginManagement>
  </build>

  在子模塊繼承pluginManagement后的插件配置

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

 

聚合與繼承的關系

區別 :

1.對於聚合模塊來說,它知道有哪些被聚合的模塊,但那些被聚合的模塊不知道這個聚合模塊的存在。

2.對於繼承關系的父 POM來說,它不知道有哪些子模塊繼承與它,但那些子模塊都必須知道自己的父 POM是什么。

 

共同點 :

1.聚合 POM與繼承關系中的父POM的 packaging都是pom

2.聚合模塊與繼承關系中的父模塊除了 POM之外都沒有實際的內容。

Maven聚合關系與繼承關系的比較
 
現有的實際項目往往是一個POM既是聚合POM又是父POM,這么做主要是為了方便。
 
反應堆:
  在一個多模塊的Maven項目中,反應堆是指所有模塊組成的一個構建結構。反應堆包含了各個模塊之間的繼承與依賴關系,從而能夠自動計算出合理的模塊構建順序。
<modules>  
  <module>account-email</module>  
  <module>account-persist</module>  
  <module>account-parent</module>  
</modules> 

 

  實際的構建順序為: ~parent, ~email, ~persist。

  可見構建的順序並不是聲明的順序。

  該例中account-email和account-persist都依賴於account-parent,那么account-parent就必須在另外兩個模塊之前構建。實際的構建順序是這樣的:Maven按聲明順序讀取POM,如果POM沒有依賴模塊,那么久構建該模塊,否則就先構建其依賴的模塊。,如果依賴的模塊還依賴於其他模塊,則進一步構建依賴的依賴。

  模塊之間的關系將反應堆構成一個有向非循環圖,各個模塊是該圖的節點,依賴關系構成又向邊,這個圖不允許出現循環,因此當出現A依賴於B,B又依賴於A的情況時Maven就會報錯。

 

裁剪反應堆:

mvn -h可以看到這樣一些選項:

Options:  
 -am,--also-make                        If project list is specified, also  
                                        build projects required by the  
                                        list  
 -amd,--also-make-dependents            If project list is specified, also  
 -pl,--projects <arg>                   Build specified reactor projects  
                                        instead of all projects. A project  
                                        can be specified by  
                                        [groupId]:artifactId or by its  
                                        relative path.  
 -rf,--resume-from <arg>                Resume reactor from specified  
                                        project  

  有的時候因為工程巨大,模塊很多,只想構建指定的模塊,這時候就會用到反應堆裁剪。

-pl 構建指定模塊
mvn clean install -pl accouont-email,account-persist后會得到如下幾個模塊:~email和~persist。

 

-am 選項可以同時構建所列模塊的依賴模塊。
當執行mvn clean install -pl account-email -am 后會得到如下幾個模塊:~parent和~email。

 

-amd 選項可以同時構建依賴於所列模塊的模塊。
mvn clean install -pl account-parent -amd 后會得到如下模塊:~parent、~email和~persist。

 

-rf 選項可以在完整的反應堆構建順序基礎上,指定從哪個模塊開始構建。
mvn clean install -rf account-email ,由於~email位於第三,它之后有~persist,因此會得到如下輸出模塊:~email和~persist。

 

在-pl -am或者-pl -amd的基礎上,還能應用-rf參數,以對裁剪后的反應堆再次裁剪。
mvn clean install -pl account-parent -amd -rf account-email
其中,-pl 和 -amd參數會得到:~parent, ~email和~persist模塊,在此基礎上 -rf參數制定從~email開始構建,於是會得到:~email和~persist。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM