第七節:Maven中的聚合與繼承

     Maven的聚合特性能夠把項目的各個模塊聚合在一起構建,而Maven的繼承特性則能幫助抽取各模塊間相同的依賴和插件配置,還能促進各個模塊之間配置的一致性。

聚合:
     我們在開發過程中,將項目拆分成獨立的子模塊,每個模塊都是一個獨立的maven project,在開始的時候我們可以獨立的編譯和測試運行每個模塊,但是我們期望能夠使用簡單的操作來完成所有項目的編譯等工作,這時Maven給出了聚合的配置方式。我們可以建立一個專門負責聚合工作的Maven project — aggregator,然後通過該模塊構建整個項目的所有模塊。
     該聚合項目特徵以及約定:
  • 該aggregator本身也做爲一個Maven項目,它必須有自己的POM
  • 約定:爲了方便構建,通常將聚合模塊放在項目目錄層的最頂層,其它子模塊作爲其子目錄存在。這樣當我們打開項目的時候,第一個看到的就是聚合模塊的POM。
  • 聚合模塊的版本和被聚合模塊版本需一致
  • 它的打包方式必須爲:pom,即<packaging>pom</packaging>
  • 引入了新的元素:<modules>及其下的<module>,用戶可以在一個打包方式爲POM的Maven項目下聲明任意數量的module元素來實現模塊的聚合。我們聲明<module>child-project-A</module>,那麼聚合項目的POM就會默認去./child-project-A的目錄下去尋找子模塊,所以在module中聲明的子模塊應與聚合項目的POM處於同一目錄下。如果我們不遵循約定,將子模塊放於跟聚合模塊同一個目錄下,則modules的聲明需要改成<module>../child-project-A</module>.
  • 聚合模塊的內容僅僅是一個pom.xml文件,因爲它只是用來幫助其它模塊構建的工具,本身並沒有實質的內容,所以它不包含src/main/java、src/test/java等目錄.
     

繼承:
     我們在項目開發的過程中,可能多個模塊獨立開發,但是多個模塊可能依賴相同的元素或者需要引入相同的插件,比如說每個模塊都需要Junit,使用spring的時候,其核心jar也必須都被引入,在編譯的時候,maven-compiler-plugin插件也要被引入,這在每一個子模塊裏都是需要配置的,但是通過POM繼承,我們可以抽取出重複的配置,精簡代碼。

     我們可以建立一個專門負責繼承工作的父模塊 — parent,他有以下特徵:
  • 該parent本身也做爲一個Maven項目,它必須有自己的POM
  • 由於它只是爲了消除配置的重複,所以繼承模塊的內容僅僅是一個pom.xml文件,本身並沒有實質的內容
  • 它的打包方式必須爲:pom,即<packaging>pom</packaging>

     繼承他的子模塊有以下特徵:
  • 在繼承他的子模塊的pom文件中,我們用<parent>元素來聲明父模塊,<parent>元素下的子元素groupId,artifactId,version指定了父模塊的座標,<relativePath>元素指定了父模塊pom文件的路徑(相對於該子模塊的pom),
          其默認值爲../,相當於去上一層目錄找父pom。但是有時候會有問題,例如我們只從倉庫中遷出了一個子模塊,此時
          <relativePath>元素多半就失效了,子模塊只能根據父模塊的座標再去倉庫中尋找。
  • 子模塊必須顯示聲明artifactId,他隱式得從父模塊繼承了groupId和version兩個元素,只要當子模塊與父模塊的這兩個元素不一致時,才需要顯式聲明他們。


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

依賴管理:
     由上我們可知dependencies是可以被繼承的,我們就想到把幾個子模塊共同依賴的元素A轉移到parent中,這樣我們又進一步的優化了配置。可是問題也隨之而來,如果有一天又創建了一個繼承parent的子模塊,但是這個模塊不需要依賴元素A,n那這時候如何處理?
     在父模塊的POM中dependencyManagement元素幫我們解決了這個問題。我們在dependencyManagement元素配置
依賴(同樣是使用dependencies,dependency元素),但是這裏(父模塊的POM中)聲明的依賴不會給父模塊引入依賴也不會給子模塊引入依賴,這段配置會被繼承,子模塊只有在POM中顯式得聲明依賴的groupId與artifactId,才能得到我們從父模塊中繼承而來的完整的依賴配置(例如包含了版本號,依賴範圍等),如果不聲明,即使依賴已經在父模塊的dependencyManagement中被聲明瞭,但是也不會有什麼實際的效果。       

     通過這樣的配置,我們可以統一項目範圍中依賴的版本,降低各個子模塊間由於依賴版本不一樣可能引起的衝突。
     更進一步,如果我們有多個父模塊,那又該怎麼抽取出各個父模塊POM文件中重複的配置呢?我們只要在各個父模塊POM文件中引入這些配置就好了。這裏使用了一個新的依賴範圍:import,並且設置這個依賴的type爲pom,代碼如下:


插件管理:
     類似於管理依賴的dependencyManagement,Maven提供了pluginManagement來管理插件,他的機制和dependencyManagement一樣,當子模塊需要不同的插件配置,可以自行配置以覆蓋父模塊的pluginManagement配置。
<project>
    ...
    <build>
        <pluginManagement>
            <plugins>
                <plugin>
                    <artifactId>maven-assembly-plugin</artifactId>
                    <version>2.2-beta-2</version>
                    <executions>
                        <execution>
                            <id>create-project-bundle</id>
                            <phase>package</phase>
                            <goals>
                                <goal>single</goal>
                            </goals>
                            <configuration>
                                <descriptorRefs>
                                    <descriptorRef>project</descriptorRef>
                                </descriptorRefs>
                            </configuration>
                        </execution>
                    </executions>
                </plugin>
            </plugins>
        </pluginManagement>
	</build> 
	...
</project>
 
<build>
    <plugins>
        <plugin>
            <artifactId>maven-assembly-plugin</artifactId>
        </plugin>
    </plugins>
</build>

繼承和聚合總結:
     對於聚合模塊來說,它知道有哪些被聚合的模塊,而對於被聚合的模塊來說,它們不知道被誰聚合了,也不知道它的存在
     對於繼承關係的父POM來說,它不知道自己被哪些子模塊繼承了,對於子POM來說,它必須知道自己的父POM是誰
     在一些實踐中我們會發現:一個POM既是聚合POM,又是父POM,這麼做主要是爲了方便。

約定優於配置:
     這是Maven最核心的設計理念之一,他大大簡化了我們需要手動配置的內容,我們舉個例子:Maven中約定了源碼目錄爲src/main/java/,編譯輸出目錄爲target/classes/,有了這個約定,我們就不再需要手動創建這些目錄,Maven會自動創建他們,在執行像mvn clean install這樣的命令時,只要按照約定,我們不需要額外配置什麼,這條命令就可以用來構建幾乎任何的Maven項目。

反應堆:
     反應堆是指所有模塊組成的一個構建結構,包含了各個模塊之間的依賴和繼承關係,能夠計算出合理的模塊構建順序。
     構建順序:按照聚合項目中<modules>中聲明<module>元素的順序來讀取各個子模塊的POM文件,如果POM文件沒有依賴模塊(父模塊),那麼就構建該模塊,否則就先構建其依賴模塊,如果該依賴還依賴於其他模塊,則進一步先構建依賴的依賴模塊。
     當我們想僅僅構建完整反應堆中的某些模塊時,我們需要調用以下命令:
  • -am(also-make):同時還會構建所列項目的依賴模塊(父模塊)
  • -amd(also-make-dependents):同時還會構建所列模塊的子模塊
  • -pl(-project)<arg..> : 構建指定模塊,模塊間用逗號分隔
  • -rf(resume-from)<arg> :在完整的反應堆構建順序基礎上指定從哪個模塊開始構建
    假設有child-A,child-B依賴於parent,完整的反應堆構建順序爲:parent ---> child-A —> child-B
     mvn clean install -pl child-A -am:此時會先構建parent,在構建child-A
     mvn clean install -pl child-A,child-B:此時會構建child-A和child-B,但是不會構建parent
     mvn clean install -pl parent -amd:此時會先構建parent,然後再構建child-A和child-B
     mvn clean install -pl child-A -amd:此時會從完整的反應堆構建順序的child-A開始到child-B

     
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章