Maven實戰讀書筆記(8)

何爲Maven的生命週期?html

1Maven從大量項目和構建工具中學習和反思,而後總結了一套高度完善的、易擴展的生命週期java

2、這個生命週期包含了項目的清理、初始化、編譯、測試、打包、集成測試、驗證、部署和站點生成等幾乎全部的構建步驟算法

3Maven的生命週期是抽象的,這意味着生命週期自己不作任何實際的工做,實際的任務(如編譯源代碼)都是交由插件來完成的apache

 

Maven的這種思想與設計模式的模板方法很是類似設計模式

模板方法模式在父類中定義算法的總體結構,子類能夠經過實現或者重寫父類的方法來控制實際的行爲,這樣既保證了算法有足夠的可擴展性,又可以嚴格控制算法的總體結構服務器

 

模擬生命週期的模板方法抽象類框架

public abstract class AbstractBuild {maven

       public void build() {ide

              initialize();工具

              compile();

              test();

              packages();

              integrationTest();

              deploy();

       }

       protected abstract void initialize();

       protected abstract void compile();

       protected abstract void test();

       protected abstract void packages();

       protected abstract void integrationTest();

       protected abstract void deploy();

}

對上面的代碼進行解釋:

1build()方法定義了整個構建的過程,依次初始化、編譯、測試、打包(因爲package Java關鍵字衝突,這裏使用了單詞packages)、集成測試和部署

2、可是這個類中沒有具體實現初始化、編譯、測試等行爲,它們都交由子類去實現

 

Maven定義生命週期和插件機制的好處是?

1、保證了全部Maven項目有一致的構建標準

2、經過默認插件簡化和穩定了實際項目的構建

3、此外,該機制還提供了足夠的擴展空間,用戶能夠經過配置現有插件或者自行編寫插件來自定義構建行爲

 

Maven的三套生命週期

初學者每每會覺得Maven的生命週期是一個總體,其實否則,Maven擁有三套相互獨立的生命週期,它們分別爲cleandefaultsite

1clean生命週期的目的是清理項目

2default生命週期的目的是構建項目

3site的生命週期的目的是創建項目站點

 

聲明週期與階段(phase)

每一個生命週期包含一些階段 (phase),這些階段是有順序的,而且後面的階段依賴於前面的階段,用戶和Maven最直接的交互方式就是調用這些生命週期階段

 

clean生命週期的階段有哪些?

clean生命週期,主要包含的階段有pre-cleancleanpost-clean

當用戶調用pre-clean的時候,只有pre-clean階段得以執行

當用戶調用clean的時候,pre-cleanclean階段會以順序執行

當用戶調用post-clean的時候,pre-cleancleanpost-clean會得以順序執行

 

注:生命週期階段的先後是依賴關係,但三套生命週期自己是相互獨立的,用戶能夠僅僅調用clean生命週期的某個階段,或者僅僅調用default生命週期的某個階段,而不會對其餘生命週期產生任何影響,例如,當用戶調用clean生命週期的clean階段的時候,不會觸發default生命週期的任何階段,反之亦然,當用戶調用default生命週期的compile階段的時候,也不會觸發clean生命週期的任何階段

 

clean生命週期的詳細信息

clean生命週期的目的是清理項目,它包含三個階段:

1pre-clean執行一些清理前須要完成的工做

2clean清理上一次構建生成的文件

3post-clean執行一些清理後須要完成的工做

 

default生命週期的詳細信息

default生命週期定義了真正構建時所須要執行的全部步驟,它是全部生命週期中最核心的部分,其包含的階段以下,只對重要的階段進行解釋:

1validate

2initialize

3generate-sources

4process-sources 處理項目主資源文件,通常來講,是對src/main/resources目錄的內容進行變量替換等工做後,複製到項目輸出的主classpath目錄中

5generate-resources

6process-resources

7compile 編譯項目的主源碼。通常來講,是編譯src/main/java目錄下的Java文件至項目輸出的主classpath目錄中

8process-classes

9generate-test-sources

10process-test-sources 處理項目測試資源文件。通常來講,是對src/test/resources 目錄的內容進行變量替換等工做後,複製到項目輸出的測試classpath目錄中

11generate-test-resources

12process-test-resources

13test-compile 編譯項目的測試代碼。通常來講,是編譯src/test/java 目錄下的Java文件至項目輸出的測試classpath目錄中

14process-test-classes

15test 使用單元測試框架運行測試,測試代碼不會被打包或部署

16prepare-package

17package 接受編譯好的代碼,打包成可發佈的格式,如JAR

18pre-integration-test

19integration-test

20post-integration-test

21verify

22install 將包安裝到Maven本地倉庫,供本地其餘Maven項目使用

23deploy 將最終的包複製到遠程倉庫,供其餘開發人員和Maven項目使用

對於上面未解釋的階段,請參閱官方的解釋:

http://maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html

 

site生命週期的詳細信息

site生命週期的目的是創建和發佈項目站點,Maven可以基於POM所包含的信息,自動生成一個友好的站點,方便團隊交流和發佈項目信息

該生命週期包含以下階段:

1pre-site 執行一些在生成項目站點以前須要完成的工做

2site 生成項目站點文檔

3post-site 執行一些在生成項目站點以後須要完成的工做

4site-deploy 將生成的項目站點發布到服務器上

 

命令行與生命週期

從命令行執行Maven任何的最主要方式就是調用Maven的生命週期階段,須要注意的是,各個生命週期是相互獨立的,而一個生命週期的階段是有先後依賴關係的。

下面以一些常見的Maven命令爲例,解釋其執行的生命週期階段:

1mvn clean:該命令調用clean生命週期的clean階段,實際執行的階段爲clean生命週期的pre-cleanclean階段

2mvn test:該命令調用default生命週期的test階段,實際執行的階段爲default生命週期的validateinitialize等,直到test的全部階段,這也解釋了爲何在執行測試的時候,項目的代碼可以自動得以編譯

3mvn clean install:該命令調用clean生命週期的clean階段和default生命週期的install階段。實際執行的階段爲clean生命週期的pre-cleanclean階段,以及default生命週期的從validateinstall的全部階段。該命令結合了兩個生命週期,在執行真正的項目構建以前清理項目是一個很好的實踐

4mvn clean deploy site-deploy:該命令調用clean生命週期的clean階段、default生命週期的deploy階段,以及site生命週期的site-deploy階段。實際執行的階段爲clean生命週期的pre-cleanclean階段,default生命週期的全部階段,以及site生命週期的全部階段。該命令結合了Maven全部三個生命週期,且deploydefault生命週期的最後一個階段,site-deploysite生命週期的最後階段

 

Maven的核心

Maven的核心僅僅定義了抽象的生命週期,具體的任務是交由插件完成的,插件以獨立的構件形式存在,所以,Maven核心的分發包只有不到3MB的大小,Maven會在須要的時候下載並使用插件

 

舉例說明插件maven-dependency-plugin

對於插件自己,爲了可以複用代碼,它每每可以完成多個任務

maven-dependency-plugin插件可以基於項目依賴作不少事情:

1、它可以分析項目依賴,幫助找出潛在的無用依賴

2、它能列出項目的依賴樹,幫助分析依賴來源

3、它可以列出項目全部已解析的依賴等等

 

那麼,爲何這樣設計,一個插件有不少功能呢?

爲每一個這樣的功能編寫一個獨立的插件顯然是不可取的,由於這些任務背後有不少能夠複用的代碼,所以,這些功能彙集在一個插件裏,每一個功能就是一個插件目標

 

maven-dependency-plugin插件的目標是指?

maven-dependency-plugin有十多個目標,每一個目標對應了一個功能,上述提到幾個功能分別對應的插件目標爲dependencyanalyzedependency:treedependency:list,這是一種通用的解法,冒號前面是插件前綴,冒號後面是該插件的目標。相似地,還能夠寫出compile:compile (這是maven-compiler-plugincompile目標) surefire:test (這是maven-surefire-plugintest目標)

 

什麼是插件綁定?

Maven的生命週期與插件相互綁定,用以完成實際的構建任務。具體而言,是生命週期的階段與插件的目標相互綁定,以完成某個具體的構建任務

例如:項目編譯這一任務,它對應了default生命週期的compile這一階段,而maven-compile-plugin這一插件的compile目標可以完成該任務,所以,將它們綁定,就能實現項目編譯的目:

生命週期階段與插件目標綁定

 

爲何須要內置綁定?

爲了能讓用戶幾乎不用任何配置就能構建Maven項目,Maven的核心爲一些主要的生命週期階段綁定了不少插件的目標,當用戶經過命令行調用生命週期階段的時候,對應的插件目標就會執行相應的任務

 

clean生命週期階段與插件目標的綁定關係

clean生命週期僅有pre-cleancleanpost-clean三個階段,其中的cleanmaven-clean綁定。maven-clean-plugin僅有clean這一個目標,其做用就是刪除項目的輸出目錄

生命週期階段

插件目標

Pre-clean


Clean

Maven-clean-plugin:clean

Post-clean


 

site生命週期階段與插件目標的綁定關係

site生命週期有pre-sitesitepost-sitesite-deploy四個階段,其中,sitemaven-site-plugin:site相互綁定,site-deploymaven-site-plugin:depoy相互綁定。maven-site-plugin有不少目標,其中,site目標用來生成項目站點,deploy目標用來將項目站點部署到遠程服務器上

生命週期階段

插件目標

Pre-site


Site

Maven-site-plugin:site

Post-site


Site-deploy

Maven-site-plugin:deploy

 

default生命週期與插件目標的綁定關係

default生命週期與插件目標的綁定關係要稍微複雜一些,這是由於對於任何項目,例如jar項目和war項目,它們的項目清理和站點生成任務是同樣的,不過構建過程會有區別,jar項目須要打成jar包,而war項目須要打包war

因爲項目的打包類型會影響構建的具體過程,所以,default生命週期的階段與插件目標的綁定關係由項目打包類型決定,打包類型是經過POM中的packing元素定義的。最多見、最重要的打包類型是jar,它也是默認的打包類型

 

default生命週期的內置插件綁定歡喜及具體任務 (打包類型:jar)

生命週期階段

插件目標

執行任務

Process-resources

Maven-resources-plugin:resources

複製主資源文件至主輸出目錄

Compile

Maven-compiler-plugin:compile

編譯主代碼至主輸出目錄

Process-test-resources

Maven-resources-plugin:testResources

複製測試資源文件至測試輸出目錄

Test-compile

Maven-compile-plugin:testCompile

編譯測試代碼至測試輸出目錄

Test

Maven-surefire-plugin:test

執行測試用例

Package

Maven-jar-plugin:jar

建立項目jar

Install

Maven-install-plugin:install

將項目輸出構件安裝到本地倉庫

Deploy

Maven-deploy-plugin:deploy

將項目輸出構件部署到遠程倉庫

上表只列出了擁有插件的綁定關係的階段,default生命週期還有不少其餘階段

 

若是沒有綁定任何插件的目標呢?

有些生命週期階段沒有綁定任何插件的目標,所以也沒有任何實際行爲

 

除了默認的打包類型jar,還有其餘說明你的嗎?

除了默認的打包類型jar,常見的打包類型還有warpommaven-pluginear

他們的default生命週期與插件目標的綁定關係可參閱Maven官方文檔:

http://maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html#Built-in_Lifecycle_Bindings

 

什麼是自定義綁定方式?

除了內置綁定之外,用戶還可以本身選擇將某個插件目標綁定到生命週期的某個階段上,這種自定義綁定方式能讓Maven項目在構建過程當中執行更多更豐富特點的任務

 

一個常見的例子

一個常見的例子是建立項目的源碼jar包,內置的插件綁定關係中並無涉及這一任務,所以須要用戶自行配置

maven-source-plugin能夠幫助咱們完成該任務,它的jar-no-fork目標可以將項目的主代碼打包成jar文件,能夠將其綁定到default生命週期的verify階段上,在執行完集成測試後和安裝構件以前建立源碼jar

配置以下

<build>

       <plugins>

              <plugin>

                     <groupId>org.apache.maven.plugins</groupId>

                     <artifactId>maven-source-plugin</artifactId>

                     <version>2.1.1</version>

                     <executions>

                            <execution>

                                   <id>attach-sources</id>

                                   <phase>verify</phase>

                                   <goals>

                                          <goal>jar-no-fork</goal>

                                   </goals>

                            </execution>

                     </executions>

              </plugin>

       </plugins>

</build>

對上述配置進行解釋:

1、在POMbuild元素下的plugins子元素中聲明插件的使用,該例中用到的是maven-source-plugin

2、其groupIdorg.apache.maven.plugins,這也是Maven官方插件的groupId,緊接着artifactIdmaven-source-pluginversion2.1.1,對於自定義綁定的插件,用戶老是應該聲明一個非快照版本,這樣能夠避免因爲插件版本變化形成的構建不穩定性

3、除了基本的插件座標聲明外,還有插件執行配置,executions下每一個execution子元素能夠用來配置執行一個任務

4、該例中配置了一個idattach-sources的任務,經過phrase配置,將其綁定到verify生命週期階段上,再經過goals配置指定要執行的插件目標

 

對於上述配置的一個細節須要注意

有時候,即便不經過phase元素配置生命週期階段,插件目標也可以綁定到生命週期中去。例如,能夠嘗試刪除上述配置中的phase一行,再次執行mvn verify,仍然能夠看到maven-source-plugin:jar-no-fork得以執行,出現這種現象的緣由是:有不少插件的目標在編寫時已經定義了默認綁定階段。可使用maven-help-plugin查看插件詳細信息,瞭解插件目標的默認綁定階段

 

如何使用maven-help-plugin插件查看插件目標的默認綁定階段?

執行命令:

mvn help:describe -Dplugin = org.apache.maven.plugins:maven-source-plugin:2.1.1-Ddetail

須要在pom.xml目錄執行此命令

在列出的信息中可能會出現,Bound to phase:package一行,它表示該目標默認綁定的生命週期階段(這裏是package),也就是說,當用戶配置使用maven-source-pluginjar-no-fork目標的時候,若是不指定phase參數,該目標就會被綁定到package階段

 

若是多個目標被綁定到同一個階段,它們的執行順序會是怎樣?

當多個目標被綁定到同一個階段,這些插件聲明的前後順序決定了目標的執行順序

 

關於插件目標的配置

完成了插件和生命週期的綁定,用戶還能夠配置插件目標的參數,進一步調整插件目標所執行的任務,以知足項目的需求。幾乎全部的Maven插件的目標都有一些可配置的參數,用戶能夠經過命令行和POM配置等方式來配置這些參數

 

如何使用命令行的方式修改插件的配置?

在平常Maven使用中,咱們會常常從命令行輸入並執行Maven命令。在這種狀況下,若是能方便地更改某些插件的行爲,無疑會十分方便

不少插件目標的參數都支持從命令行配置,用戶能夠在Maven命令中使用-D參數,並伴隨一個參數鍵 = 參數值的形式,來配置插件目標的參數

例如,maven-surefire-plugin提供了一個maven.test.skip參數,當其值爲true的時候,就會跳過執行測試,因而,在運行命令的時候,加上以下-D參數就能跳過測試:

mvn install -Dmaven.test.skip=true

 

這裏的-D參數是什麼意思?

參數-DJava自帶的,其功能是經過命令行設置一個Java系統屬性,Maven簡單地重用了該參數,在準備插件的時候檢查系統屬性,便實現了插件參數的配置

 

POM中插件全局配置

並非全部的插件參數都適合從命令行配置,有些參數的值從項目建立到項目發佈都不會改變,或者說不多改變,對於這種狀況,在POM文件中一次性配置就顯然比重複的命令行輸入要方便

好比,咱們一般會須要配置maven-compiler-plugin告訴它編譯Java 1.7版本的源文件,生成與JVM 1.5兼容的字節碼文件

POM中對插件進行全局配置

<build>

       <plugins>

              <plugin>

                     <groupId>org.apache.maven.plugins</groupId>

                     <artifactId>maven-compiler-plugin</artifactId>

                     <version>2.1</version>

                     <configuration>

                            <source>1.7</source>

                            <target>1.7</target>

                     </configuration>

              </plugin>

       </plugins>

</build>

這樣,無論綁定到compile階段的maven-compiler-plugin:compile任務,仍是綁定到test-compile階段的maven-compiler-plugin:testCompiler任務,就都可以使用該配置,基於Java1.7版本進行編譯

 

POM中插件任務配置

除了爲插件配置全局的參數,用戶還能夠爲某個插件任務配置特定的參數。以maven-antrun-plugin爲例,它有一個目標run,能夠用來在Maven中調用Ant任務。用戶將maven-antrun-plugin:run綁定到多個生命週期階段上,再加以不一樣的配置,就可讓Maven在不一樣的生命階段執行不一樣的任務

POM中對插件進行任務配置

<build>

       <plugins>

              <plugin>

                     <groupId>org.apache.maven.plugins</groupId>

                     <artifactId>maven-antrun-plugin</artifactId>

                     <version>1.3</version>

                     <executions>

                            <execution>

                                   <id>ant-validate</id>

                                   <phase>validate</phase>

                                   <goals>

                                          <goal>run</goal>

                                   </goals>
                                   <configuration>

                                          <tasks>

                                                 <echo>I'm bound to validate phase.</echo>

                                          </tasks>

                                   </configuration>

                            </execution>

                            <execution>

                                   <id>ant-verify</id>

                                   <phase>verify</phase>

                                   <goals>

                                          <goal>run</goal>

                                   </goals>
                                   <configuration>

                                          <tasks>

                                                 <echo>I'm bound to verify phase.</echo>

                                          </tasks>

                                   </configuration>

                            </execution>

                     </executions>

              </plugin>

       </plugins>

</build>

對上述配置進行解釋:

1maven-antrun-plugin:runvalidate階段綁定,從而構成一個idant-validate的任務

2、插件全局配置中的configuration元素位於plugin元素下面,而這裏的configuration元素則位於execution元素下,表示這是特定任務的配置,而非插件總體的配置

3、這個ant-validate任務配置了一個echo Ant任務,向命令行輸出一段文字,表示該任務是綁定到validate階段的,第二個任務的idant-verify,它綁定到了verify階段,一樣它也輸出一段文字到命令行,告訴該任務綁定到了verrify階段

 

關於插件存在的問題說明

僅僅理解如何配置使用插件是不夠的,當遇到一個構建任務的時候,用戶還須要知道去哪裏尋找合適的插件,以幫助完成任務。找到正確的插件以後,還要詳細瞭解該插件的配置點。因爲Maven的插件很是多,並且這其中的大部分沒有完善的文檔,所以,使用正確的插件並進行正確的配置,其實並非一件容易的事

 

如何在線查找插件信息?

基本上全部的主要的Maven插件都來自ApacheCodehaus,因爲Maven自己是屬於Apache軟件基金會的,所以它有不少官方的插件,天天都有成千上萬的Maven用戶在使用這些插件,它們具備很是好的穩定性

詳細的列表地址:

http://maven.apache.org/plugins/index.html

全部官方插件下載地址:

http://repo1.maven.org/maven2/org/apache/maven/plugins

 

託管於Codehaus上的Mojo項目

除了Apache上的官方插件以外,託管於Codehaus上的Mojo項目也提供了大量的Maven插件,須要注意的是,這些插件的文檔和可靠性相對較差

詳細列表能夠訪問地址:

http://mojo.codehaus.org/plugins.html

CodehausMaven插件下載地址:

http://repository.codehaus.org/org/code-haus/mojo/

 

另外,上述兩個站點提供的插件很是多,而實際使用中經常使用的插件遠不會是這個數量

 

使用maven-help-plugin描述插件

除了訪問在線的插件文檔以外,還能夠藉助maven-help-plugin來獲取插件的詳細信息

能夠運行以下命令來獲取maven-compiler-plugin 2.1版本的信息:

mvn help:describe -Dplugin=org.apache.maven.plugins:maven-compiler-plugin:2.1

你可能會發現一行Goal Prefix: compiler,這是目標前綴 (Goal Prefix),其做用是方便在命令行直接運行插件,maven-compiler-plugin的目標前綴是compiler

在描述插件的時候,還能夠省去版本信息,讓Maven自動獲取最新版原本進行表述:

mvn help:describe -Dplugin=org.apache.maven.plugins:maven-compiler-plugin

進一步簡化

mvn help:describe -Dplugin= compiler

若是想僅僅描述某個插件目標的信息,能夠加上goal參數

mvn help:describe -Dplugin= compiler -Dgoal=compile

若是想讓maven-help-plugin輸出更詳細的信息,能夠加上detail參數:

mvn help:describe -Dplugin= compiler -Ddetail

 

使用mvn -h來顯示mvn命令幫助

你可能會看到以下信息:

usage:mvn [options] [<goals>] [<phase(s)>]

Options:

...

該信息告訴咱們mvn命令的基本用法,options表示可用的選項,mvn命令有20多個選項

除了選項外,mvn命令後面能夠添加一個或者多個goalphase,它們分別是指插件目標和生命週期階段

 

爲何Maven支持直接從命令行調用插件目標?

Maven支持這種方式是由於有些任務不適合綁定在聲明週期上

例如maven-help-plugin:describe,咱們不須要在構建項目的時候描述插件信息

又如maven-dependency-plugin:tree,咱們也不須要在構建項目的時候去顯示依賴樹

 

那麼如何使用上述兩個插件目標?

你能夠在命令行輸入:

mvn help:describe -Dplugin=compiler

mvn dependency:tree

 

上面的兩條命令有個疑問?

describemaven-help-plugin的目標沒錯,但冒號前面的help是什麼呢?它既不是groupId、也不是artifactId

Maven是如何根據該信息找到對應版本插件的呢?

爲何不是maven-dependency-plugin:tree,而是dependency:tree

嘗試回答上述問題,執行下面兩條命令:

mvn org.apache.maven.plugins:maven-help-plugin:2.1:describe -Dplugin=compiler

mvn org.apache.maven.plugins:maven-dependency-plugin:2.1:tree

這兩條命令比較好理解,插件的groupIdartifactIdversion以及goal都得以清晰描述

它們的效果與以前的兩個命令基本是同樣的,但顯然前面的命令更加簡潔

爲了達到該目的,Maven引入了目標前綴的概念

helpmaven-help-plugin的目標前綴

dependencymaven-dependency-plugin的前綴

有了插件前綴,Maven就能找到對應的artifactId,不過,除了artifactIdMaven還須要獲得groupIdversion才能精肯定位到某個插件,如何解釋這個過程?

 

Maven插件解析機制

爲了方便用戶使用和配置插件,Maven不須要用戶提供完整的插件座標信息,就能夠解析獲得正確的插件,Maven的這一特性是一把雙刃劍,雖然它簡化了插件的使用和配置,可一旦插件的行爲出現異常,用戶就很難快速定位處處問題的插件構件

例如mvn help:system這樣一條命令,它到底執行了什麼插件?該插件的groupIdartifactIdversion分別是什麼?這個構件是從哪裏來的?等等問題

 

插件倉庫

與依賴構件同樣,插件構件一樣基於座標存儲在Maven倉庫中,在須要的時候,Maven會從本地倉庫尋找插件,若是不存在,則從遠程倉庫查找,找到插件以後,再下載到本地倉庫使用

 

Maven會區別對待依賴的遠程倉庫和插件的遠程倉庫

1、當Maven須要的依賴在本地倉庫不存在時,它會去所配置的遠程倉庫查找

2、當Maven須要的插件在本地倉庫不存在時,它就不會去這些遠程倉庫查找

3、不一樣於repositories及其repository子元素,插件的遠程倉庫使用pluginRepositoriesPluginRepository配置

 

Maven內置的插件倉庫配置

<pluginRepositories>

       <pluginRepository>

              <id>central</id>

              <name>Maven Plugin Repository</name>

              <url>http://repo1.maven.org/maven2</url>

              <layout>default</layout>

              <snapshots>

                     <enabled>false</enabled>

              </snapshots>

              <releases>

                     <updatePolicy>never</updatePolicy>

              </releases>

       </pluginRepository>

</pluginRepositories>

 

關於插件倉庫的說明

1、通常中央倉庫所包含的插件徹底夠用,不須要配置其餘插件倉庫

 

插件的默認groupId

1、在POM中配置插件的時候,若是該插件是Maven的官方插件,即(若是其groupIdorg.apache.maven,plugins),就能夠省略groupId配置。好比像下面這樣:

<build>

       <plugins>

              <plugin>

                     <artifactId>maven-compiler-plugin</artifactId>

                     <version>2.1</version>

                     <configuration>

                            <source>1.7</source>

                            <target>1.7</target>

                     </configuration>

              </plugin>

       </plugins>

</build>

2、不推薦使用這一機制

 

Maven的解析插件版本機制

一樣是爲了簡化插件的配置和使用,在用戶沒有提供插件版本的狀況下,Maven會自動解析插件版本

1Maven在超級POM中爲全部核心插件設定了版本,超級POM是全部Maven項目的父POM,全部項目都繼承這個超級POM的配置,所以,即便用戶不加任何配置,Maven使用核心插件的時候,它們的版本就已經肯定了。這些插件包括maven-clean-pluginmaven-compiler-pluginmaven-surefire-plugin

2、若是用戶使用某個插件時沒有設定版本,而這個插件又不屬於核心插件的範疇,Maven就會去檢查全部的倉庫中可用的版本,而後作出選擇,以maven-compiler-plugin爲例,它在中央倉庫的倉庫元數據爲:

http://repo1.maven.org/maven2/org/apache/maven/plugins/maven-compiler-plugin/maven-metadata.xml,其代碼以下:

<?xml version="1.0" encoding="UTF-8"?>

<metadata>

       <groupId>org.apache.maven.plugins</groupId>

       <artifactId>maven-compiler-plugin</artifactId>

       <versioning>

              <latest>2.1</latest>

              <release>2.1</release>

              <versions>

                     <version>2.0-beta-1</version>

                     <version>2.0</version>

                     <version>2.0.2</version>

                     <version>2.1</version>

              </versions>

              <lastUpdated>20100102092331</lastUpdated>

       </versioning>

</metadata>

3Maven遍歷本地倉庫和全部的遠程插件倉庫,將該路徑下的倉庫元數據歸併後,就能計算出lastestrelease的值。lastest表示全部倉庫中該構件的最新版本,而release表示最新的非快照版本。在Maven 2中,插件的版本會被解析至latest,也就是說,當用戶使用某個非核心插件且沒有聲明版本的時候,Maven會將版本解析爲全部可用倉庫中的最新版本,而這個版本也多是快照版本

4、當插件的版本爲快照版本時,就會出現潛在的問題。Maven會基於更新的策略,檢查並使用快照的更新。某個插件可能昨天還用的好好的,今天就出錯了,其緣由就是這個快照版本的插件發生了變化。爲了防止這類問題,Maven3調整了解析機制,當插件沒有聲明版本的時候,再也不解析至latest,而是使用release。這樣就能夠避免因爲快照頻繁更新而致使的插件行爲不穩定

5、依賴Maven解析插件版本實際上是不推薦的作法,即便Maven 3將版本解析到最新的非快照版,也仍是會有潛在的不穩定性。例如,可能某個插件發佈了一個新的版本,而這個版本的行爲與以前的版本發生了變化,這種變化可能致使項目構建失敗。所以,使用插件的時候,應該一直顯式地設定版本,這也解釋了Maven爲何要在超級POM中爲核心插件設定版本

 

Maven如何解析插件前綴?

前面說到mvn命令行支持使用插件前綴來簡化插件的調用,如今解釋Maven如何根據插件前綴解析獲得插件的座標

插件前綴與groupId:artifactId是一一對應的,這種匹配關係存儲在倉庫元數據中。與以前提到的groupId/artifactId/maven-metadata.xml不一樣,這裏的倉庫元數據爲groupId/maven-metadata.xml,那麼這裏的groupId是什麼呢?

咱們知道,插件都位於如下兩個地址:

http://repo1.maven.org/maven2/org/apache/maven/plugins

http://repository.codehaus.org/org/code-haus/mojo/

相應地,Maven在解析插件倉庫元數據的時候,會默認使用org.apache.maven.pluginsorg.codehaus.mojo兩個groupId,也能夠經過配置settings.xmlMaven檢查其餘groupId上的插件倉庫元數據:

<settings>

       <pluginGroups>

              <pluginGroup>com.your.plugins</pluginGroup>

       </pluginGroups>

</settings>

基於該配置,Maven就不只僅會檢查org/apache/maven/plugins/maven-metadata.xmlorg/codehaus/mojo/maven-metadata.xml,還會檢查com/your/plugins/maven-metadata.xml

 

插件倉庫元數據

<metadata>

       <plugins>

              <plugin>

                     <name>Maven Clean Plugin</name>

                     <prefix>clean</prefix>

                     <artifactId>maven-clean-plugin</artifactId>

              </plugin>

              <plugin>

                     <name>Maven Compiler Plugin</name>

                     <prefix>compiler</prefix>

                     <artifactId>maven-compiler-plugin</artifactId>

              </plugin>

              <plugin>

                     <name>Maven Dependency Plugin</name>

                     <prefix>dependency</prefix>

                     <artifactId>maven-dependency-plugin</artifactId>

              </plugin>

       </plugins>

</metadata>

對於上述配置的解釋:

1、上述內容是從中央倉庫的org.apache.maven.plugins.groupId下插件倉庫元數據中截取的一些片斷,從這段數據中就能看到maven-clean-plugin的前綴爲cleanmaven-compiler-plugin的前綴爲compilermaven-dependency-plugin的前綴爲dependency

 

Maven是如何解析dependency:tree這樣的命令的?

1、當Maven解析到dependency:tree這樣的命令後,它首先基於默認的groupId歸併全部插件倉庫的元數據org/apache/maven/plugins/maven-metadata.xml

2、其次檢查歸併後的元數據,找到對應的artifactIdmaven-dependency-plugin;而後結合當前元數據的groupId org.apache.maven.plugins,而後經過上面的解析插件版本,解析到version,這時就獲得了完整的插件座標

3、若是org/apache/maven/plugins/maven-metadata.xml沒有記錄該插件的前綴,則接着檢查其餘groupId下的元數據,如org/codehaus/mojo/maven-metadata.xml,以及用戶自定義的插件組,若是全部的元數據中都不含該前綴,則報錯

相關文章
相關標籤/搜索