Maven 聚合與繼承

Maven 聚合與繼承java

1. 背景spring

在這個技術發展飛速的時代,各種用戶對軟件的要求愈來愈高,軟件自己也變得越apache

來越複雜。所以,軟件設計人員每每會採用各類方式對軟件劃分模塊,以獲得更清晰的maven

設計及更高的重用性。性能

Maven 的聚合特性可以把項目的各個模塊聚合在一塊兒構建,而 Maven 的繼承特性測試

則能幫助抽取各模塊相同的依賴和插件等配置,在簡化 pom 配置的同時,還能促進各個ui

模塊配置的一致性。url

2. 聚合插件

到目前爲止,咱們都是一個項目一個項目的構建。一個簡單的需求就出來了,咱們命令行

會想要一此構建兩個項目,而不是到兩個模塊分別執行 mvn 命令,Maven 聚合(或者

稱爲多模塊)這一特性就是爲該需求服務的。

a) 建立聚合模塊

    須要建立一個新的模塊,來聚合構建項目中其餘全部模塊。

<modelVersion>4.0.0</modelVersion><groupId>org.lichee</groupId><artifactId>lichee</artifactId><version>1.0.0</version><packaging>pom</packaging><name>lichee :: project</name><description>This is a project demo of lynch</description><inceptionYear>2013-2014</inceptionYear><modules>  <module>parent</module>  <module>core</module>  <module>common</module>  <module>support</module>  <module>test</module>  <module>simple-example</module></modules>

 

b) 聚合模塊特徵

    i.   Maven 項目

         聚合模塊自己也是一個 Maven 項目。

    ii.  目錄差別

        準確說除了其餘模塊目錄和 pom.xml,沒有其餘任何 src、test、target 等相關目錄。

   
    

    iii. pom.xml

        1) 相同的 groupId、version

        2) packaging 必須是 pom

            繼承父模塊也同樣必須是 pom。

        3) name 提供一個相對容易閱讀的名字

            配置合理的 name 字段,會讓 Maven 的構建輸出更清晰。

        4) modules

            實現聚合的最核心配置,用戶能夠經過一個打包方式爲 pom 的 Maven 項目中聲明,

            任意數量的 module 元素來實現模塊的聚合。每一個 module 的值都是一個當前 pom 的相對目錄。

        5) 模塊所處的目錄名稱與其 artifactId 一致

            文件的目錄名稱和 artifactId 相同,但不絕對,只是 module 裏面的配置,

            必須和文件目錄上的名字同樣。

        6) 推薦目錄格式

            一般將聚合模塊放在項目目錄的最頂層,其餘模塊則做爲聚合模塊的子目錄存在,

            方便用戶尋找聚合模塊來構建整個項目。

c) 解析過程

    Maven 會首先解析聚合模塊的 pom、分析要構建的模塊、並計算出一個反應堆構建順序

   (Reactor Build Order),而後根據這個順序依次構建各個模塊。

   
    

    i.   項目構建小結報告

    ii.  各個模塊構建成功與否、花費時間

    iii. 整個構建花費的時間、使用內存等

3. 繼承

不少項目中,不一樣的子模塊有着相同的 groupId、version,相同的 spring、junit等依賴,

相同的 maven-compiler-plugin 插件等配置。這就是重複,重複意味着更多的勞動和更多的潛在問題。

在 Maven 世界中,有機制能讓咱們抽取出重複的配置,這就是 pom 的繼承。

a) 建立繼承模塊

    咱們須要建立 pom 的父子結構,在父 pom 中聲明一些配置供子 pom 繼承,一處聲明,多處使用。

    父模塊:

<groupId>org.lichee</groupId><artifactId>lichee-parent</artifactId><version>1.0.0</version><packaging>pom</packaging><name>lichee :: parent</name>

 

    子模塊:

<parent><groupId>org.lichee</groupId><artifactId>lichee-parent</artifactId><version>1.0.0</version><relativePath>../parent/</relativePath></parent><artifactId>lichee-core</artifactId><packaging>jar</packaging><name>lichee :: core</name>

 

b) 繼承模塊特徵

    i.   Maven 項目

         繼承模塊自己也是一個 Maven 項目。

    ii.  目錄差別

         準確說除了 pom.xml,沒有其餘任何 src、test、target 等相關目錄。

   
    

    iii. pom.xml

        1) groupId、version

            雖然子模塊沒有聲明,不過不表明子模塊沒有這兩個屬性,隱式地從父模塊繼承了這兩個元素,

            這也就消除一些沒必要要的配置。若是子模塊須要使用和父模塊,

            不同的 groupId 或者 version 的狀況,那麼用戶徹底能夠在子模塊中顯式聲明。

            對於 artifactId 元素來講,子模塊應該顯式聲明。

        2) packaging 必須是 pom

            和聚合模塊同樣。

        3) name 提供一個相對容易閱讀的名字

             配置合理的 name 字段,會讓 Maven 的構建輸出更清晰。

        4) relativePath

            表示父模塊 pom 的相對路徑,默認值爲../pom.xml,也就是說,

            Maven默認父 pom 在上一層目錄下。若是子模塊沒有設置正確的 relativePath,

            Maven 將沒法找到父 pom,這將直接致使構建失敗。

4. 可繼承的 pom 元素

    a) groupId

        項目組 Id,項目座標的核心元素。

    b) version

        項目版本,項目座標的核心元素。

    c) description

        項目的描述信息。

    d) organization

        項目的組織信息。

    e) inceptionYear

        項目的創始年份。

     f) url

        項目的 url 地址。

    g) developers

        項目的開發者信息。

    h) contributors

        項目的貢獻者信息。

     i) distributionManagement

        項目的部署配置。

     j) issueManagement

        項目的缺陷跟蹤系統信息。

    k) ciManagement

        項目的持續集成系統信息。

     l) scm

        項目的版本控制系統信息。

   m) mailingLists

        項目的郵件信息列表。

    n) properties

        自定義的 Maven 屬性。

    o) dependencies

        項目的依賴配置。

    p) dependencyManagement

        項目的依賴管理配置。

    q) repositories

        項目的倉庫配置。

    r) build

        包括項目的源碼目錄配置、輸出目錄配置、插件配置、插件管理配置等。

    s) reporting

        包括項目的報告輸出目錄配置、報告插件配置等。

5. 依賴管理

經過 dependencies 元素,能夠將父模塊的依賴繼承到子類中,但並非每個子模塊

都須要相同的依賴。也不合理。

a) dependencyManagement

    讓子模塊繼承到父模塊的依賴配置,又能保證子模塊依賴使用的靈活性。

    在這個元素下的依賴聲明不會引入實際的依賴,不過它可以約束 dependencies 下的依賴使用。

    父模塊:

<properties>  <junit.version>4.11</junit.version>  <spring.version>3.2.5.RELEASE</spring.version>  <jdk.version>1.6</jdk.version></properties><dependencyManagement>  <dependencies>    <dependency>      <groupId>junit</groupId>      <artifactId>junit</artifactId>      <version>${junit.version}</version>      <scope>test</scope>    </dependency>    <dependency>      <groupId>org.springframework</groupId>      <artifactId>spring-context</artifactId>      <version>${spring.version}</version>    </dependency>    <dependency>      <groupId>org.springframework</groupId>      <artifactId>spring-context-support</artifactId>      <version>${spring.version}</version>    </dependency>  </dependencies></dependencyManagement>

 

    子模塊:

<dependencies>  <dependency>    <groupId>junit</groupId>    <artifactId>junit</artifactId>  </dependency>  <dependency>    <groupId>org.springframework</groupId>    <artifactId>spring-context</artifactId>  </dependency>  <dependency>    <groupId>org.springframework</groupId>    <artifactId>spring-context-support</artifactId>  </dependency></dependencies>

 

    i.   變量提取

         spring 和 junit 依賴的版本以 maven 變量的形式提取出來,不只消除了一些重複,

         也使得個依賴的版本處於更加明顯的位置。

    ii.  引入時機

         dependencyManagement 聲明的依賴不會被任何一個子模塊引入,

         不過這段配置是會被子模塊繼承的。子模塊的引入這些依賴就很簡單了。

         1) 只配置 groupId 和 artifactId

             省去 version 和 scope,這些想信息能夠被省略是由於子模塊繼承了,

             父模塊的 dependencyManagement,完整的依賴聲明在父 pom 中,

             子模塊只須要配置簡單的 groupId 和 artifactId 就能得到對應的依賴信息,

             從而引入正確的依賴。

         2) 選擇性引入依賴

             若是子模塊的 pom 中不聲明某個依賴的使用,即便該依賴已經在父 pom

             的 dependencyManagement 中聲明瞭,也不會產生任何實際的效果,

             也就是說不會被引入到子模塊的依賴中。

        3) 最佳推薦

            這種依賴管理機制彷佛不能減小太多的 pom 配置,不過仍是推薦採用這種方式。

            由於在父 pom 中使用 dependencyManagement 聲明依賴可以統一項目範圍中的依賴版本,

            子模塊在使用過程當中無需聲明版本,也不會發生多個子模塊使用的依賴版本不一致,

            這能夠下降依賴衝突的概率,對於後期升級或者修改依賴版本,也是提供了大大的便利。

        4) import 依賴範圍

            這個範圍的依賴只在 dependencyManagement 元素下才有效果,使用該範圍的依賴一般

            指向一個 pom,做用是將目標 pom 中的dependencyManagement 配置導入併合併到,

            當前 pom 的dependencyManagement 元素中。import 範圍依賴因爲其特俗性,

            通常都是指向打包類型爲 pom 的模塊。

6. 插件管理

Maven 提供了 dependencyManagement 元素幫助管理依賴,相似的,

Maven 也提供了 pluginManagement 元素幫助管理插件。

a) pluginManagement

    該元素中配置的依賴插件不會形成實際插件的行爲,當子模塊 pom 中配置了真正的plugin 元素,

    而且 groupId、artifactId 與 pluginManagement 中配置的插件匹配時,

    pluginManagement 的配置纔會影響實際的插件行爲。

    父模塊:

<pluginManagement>  <plugins>    <plugin>      <groupId>org.apache.maven.plugins</groupId>      <artifactId>maven-compiler-plugin</artifactId>      <version>3.1</version>      <configuration>        <source>1.6</source>        <target>1.6</target>        <showWarnings>true</showWarnings>      </configuration>    </plugin>  </plugins></pluginManagement>

 

    子模塊:

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

 

    i.   變量提取

         和 dependencyManagement 同樣。

    ii.  引入時機

         和 dependencyManagement 同樣。

    iii. 最佳推薦

        當項目中的多個模塊有一樣的插件配置時,應當將配置移到父 pom 的pluginManagement 元素中。

        甚至能夠要求將全部用到的插件的版本在父pom的pluginManagement元素中聲明,

        子模塊使用插件時不配置版本信息,這麼作能夠統一插件的版本,

        避免潛在的插件不一致或者不穩定問題,也便易於維護。

7. 聚合與繼承的關係

a) 相同點

     聚合 pom 和繼承關係中的父 pom 的 packaging 都必須是 pom,

     聚合模塊與繼承關係中的父模塊除了 pom 以外都沒有實際的內容。

     每每也會發現,一個 pom 既是聚合 pom,也是父 pom,這麼作主要是爲了方便,

     融合使用聚合與繼承也沒有什麼問題。

b) 不一樣點

    i.   聚合

         爲了方便快速構建項目。它知道有哪些被聚合的模塊,但那些被聚合的模塊不知道這個聚合模塊。

    ii.  繼承

         爲了消除重複配置。它不知道有哪些子模塊繼承與它,但那些子模塊都必須知道,

         本身的父 pom 是什麼。

c) 如圖所示

   
    

8. 約定優於配置

Maven 提倡「約定優於配置」(Convention Over Configuration),這是 Maven最核心的設計理念之一。

緣由之一就是使用約定能夠大量減小配置。

a) 源碼目錄爲 src/main/java/

b) 源碼資源目錄爲 src/main/resources/

c) 測試目錄爲 src/test/java/

d) 測試資源目錄爲 src/test/resources/

e) 編譯輸出目錄爲 target/classes/

f) 打包方式爲 jar

g) 包輸出目錄爲 target/

h) 超級 pom

    超級 pom 定義以上的目錄結構、核心插件設定版本。Maven 設定核心插件的緣由,

    是防止因爲插件版本的變化而形成構建的不穩定。

    遵循約定雖然損失了必定的靈活性,用戶不能隨意安排目錄結構,可是卻能減小配置。

    更重要的是,遵循約定可以幫用戶遵循構建標準。個性每每意味着犧牲通用性,

    意味着增長無謂的複雜度。

9. 反應堆

反應堆(Reactor)是指全部模塊組成的一個構建結構。對於單模塊的項目,反應堆就

是該模版自己,但對於多模塊項目來講,反應堆就包含了各模塊之間繼承與依賴的關係。

a) 反應堆的構建順序

    通常狀況按照 modules 的聲明順序,不過也有特俗狀況。Maven 按序讀取 pom,

    若是該 pom 沒有依賴模塊,那麼就構建該模塊,不然就先構建其依賴模塊,

    若是該依賴還依賴於其餘模塊,則進一步先構建依賴的依賴。

    i.   繼承或者依賴

         Maven 還須要考慮模塊之間的繼承和依賴關係。

    ii.  有向非循環圖

         模塊間的依賴關係會將反應堆構成一個有向非循環圖。

b) 裁剪反應堆

    用戶會想要僅僅構建完整反應堆中的某些個模塊。也就是用戶須要實時地裁剪反應堆。

    Maven 提供不少命令行選項支持裁剪反應堆,mvn –h 查看。

    略(不經常使用)

相關文章
相關標籤/搜索