Maven(2)--生命周期以及插件目标
maven的生命周期
maven的生命周期是抽象的,它本身并不做任何的工作。實(shí)際的工作都交由"插件"來完成。這種思想和設(shè)計(jì)模式中的模板方式。
maven內(nèi)置的生命周期:
?
maven的每個(gè)構(gòu)建步驟都可以綁定一個(gè)或多個(gè)插件行為,而且maven為大多數(shù)的構(gòu)建步驟編寫并綁定了默認(rèn)插件。
| clean | pre-clean | ? | ? | 執(zhí)行一些清理前需要完成工作 | 
| clean | clean:clean | maven-clean-plugin | 清理上一次構(gòu)建生成的文件 | |
| post-clean | ? | ? | 執(zhí)行一些清理后需要完成的工作 | |
| default | validate | ? | ? | 用于驗(yàn)證項(xiàng)目的有效性和其項(xiàng)目所需要的內(nèi)容是否具備 | 
| initialize | ? | ? | 初始化操作,比如創(chuàng)建一些構(gòu)建所需要的目錄等。 | |
| generate-sources | ? | ? | 用于生成一些源代碼,這些源代碼在compile phase中需要使用到 | |
| process-sources | ? | ? | 對(duì)源代碼進(jìn)行一些操作,例如過濾一些源代碼 | |
| generate-resources | ----packaging ear ear:generate-application-xml ----packaging maven-plugin plugin:descriptor | ? | 生成資源文件(這些文件將被包含在最后的輸入文件中) | |
| process-resources | resources:resources | maven-resources-plugin | 對(duì)資源文件進(jìn)行處理 | |
| compile | compiler:compile | maven-compiler-plugin | 對(duì)源代碼進(jìn)行編譯 | |
| process-classes | ? | ? | 對(duì)編譯生成的文件進(jìn)行處理 | |
| generate-test-sources | ? | ? | 生成測試用的源代碼 | |
| process-test-sources | ? | ? | 對(duì)生成的測試源代碼進(jìn)行處理 | |
| generate-test-resources | ? | ? | 生成測試用的資源文件 | |
| process-test-resources | resources:testResources | maven-resources-plugin | 對(duì)測試用的資源文件進(jìn)行處理 | |
| test-compile | compiler:testCompile | maven-compiler-plugin | 對(duì)測試用的源代碼進(jìn)行編譯 | |
| process-test-classes | ? | ? | 對(duì)測試源代碼編譯后的文件進(jìn)行處理 | |
| test | surefire:test | maven-surefire-plugin | 進(jìn)行單元測試 | |
| prepare-package | ? | ? | 打包前置操作 | |
| package | --- Packaging ejb / ejb3 / jar / par / rar / war ejb:ejb or ejb3:ejb3 or jar:jar or par:par or rar:rar or war:war ----packaging ear ear:ear ----packaging maven-plugin jar:jar and plugin:addPluginArtifactMetadata | ? | 打包 | |
| pre-integration-test | ? | ? | 集成測試前置操作 | |
| integration-test | ? | ? | 集成測試 | |
| post-integration-test | ? | ? | 集成測試后置操作 | |
| verify | ? | ? | 運(yùn)行任何檢查以驗(yàn)證包是否有效并符合質(zhì)量標(biāo)準(zhǔn)。 | |
| install | install:install | maven-install-plugin | 將打包產(chǎn)物安裝到本地maven倉庫 | |
| deploy | deploy:deploy | maven-deploy-plugin | 將打包產(chǎn)物安裝到遠(yuǎn)程倉庫 | |
| site | pre-site | ? | ? | 執(zhí)行一些在生成項(xiàng)目站點(diǎn)之前需要執(zhí)行的操作 | 
| site | ? | ? | 生成項(xiàng)目站點(diǎn) | |
| post-site | site:site | maven-site-plugin | 執(zhí)行一些在生成項(xiàng)目站點(diǎn)之前需要執(zhí)行的操作 | |
| site-deploy | site:deploy | maven-site-plugin | 將生成的站點(diǎn)發(fā)布到服務(wù)器上 | 
命令行與生命周期
從命令行執(zhí)行maven任務(wù)的最主要的方式就是調(diào)用maven的生命周期階段(phase)。各個(gè)生命周期是獨(dú)立的,每個(gè)生命周期指定一個(gè)階段(也可不指定),一個(gè)生命周期的階段是前后依賴的,此階段前的所有階段都會(huì)順序執(zhí)行。
maven命令格式:
?mvn [options]? [<goal(s)>] ? [<phase(s)>]
示例:
?
mvn clean
mvn test
mvn clean install
mvn clean deploy site-deploy
maven插件的目標(biāo)(goal)
maven核心僅定義了抽象的生命周期階段,具體任務(wù)由插件完成。一個(gè)插件可能有很多功能,某個(gè)功能就叫一個(gè)目標(biāo)(goal)。例如:
compiler:compile, compiler:test-compile
自定義綁定
除了內(nèi)置綁定外,用戶可以自己指定把插件綁定到哪個(gè)階段,配置如下:
<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>
命令行插件配置
可以使用maven -D參數(shù)來配置插件的參數(shù)。
mvn -install -Dmaven.test.skip=true
命令行調(diào)用插件
maven命令行:
?mvn [options]? [<goal(s)>] ? [<phase(s)>]
maven調(diào)用phases,可以執(zhí)行綁定在生命周期的階段的插件目標(biāo),但是有些任務(wù)不適合綁定到生命周期,可以直接從命令行調(diào)用插件。
例如:
mvn help:describe -Dplugin=compile
?describe是目標(biāo)(goal),help呢?help是maven-help-plugin的前綴。
插件解析機(jī)制
為了方便用戶使用和配置插件,Maven不需要用戶提供完整的插件坐標(biāo)信息,就可以解析得到正確的插件,Maven的這一特性是一把雙刃劍,雖然他簡化了插件的使用和配置,可一旦插件的行為出現(xiàn)異常,用戶就很難快速定位到問題的插件構(gòu)件。例如mvn help:system這樣一條命令,他到底執(zhí)行了什么插件?該插件的groupId、artifactId和version分別是什么?這個(gè)構(gòu)件是從哪里來的?本文就詳細(xì)介紹Maven的運(yùn)行機(jī)制,以讓其不僅知其然,更知其所以然。
插件倉庫
與依賴構(gòu)件一樣,插件構(gòu)件同樣基于坐標(biāo)存儲(chǔ)在Maven倉庫中。在需要的時(shí)候,Maven會(huì)從本地倉庫尋找插件,如果不存在,則從遠(yuǎn)程倉庫查找。找到插件之后,再下載到本地倉庫使用。
值得一提的是,Maven會(huì)區(qū)別對(duì)待依賴的遠(yuǎn)程倉庫與插件的遠(yuǎn)程倉庫。當(dāng)Maven需要的依賴在本地倉庫不存在時(shí),他會(huì)去所配置的遠(yuǎn)程倉庫查找,可是當(dāng)Maven需要的插件在本地倉庫不存在時(shí),他就不會(huì)去這些遠(yuǎn)程倉庫查找。
不同于repositories及其repository子元素,插件的遠(yuǎn)程倉庫使用pluginRepositories和pluginRepository配置。例如,Maven內(nèi)置了如下的插件遠(yuǎn)程倉庫配置,見下面所示。
<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>除了pluginRepositories和pluginRepository標(biāo)簽不同之外,其余所有子元素表達(dá)含義與依賴遠(yuǎn)程倉庫配置完全一樣。我們甚至看到,這個(gè)默認(rèn)插件倉庫的地址就是中央倉庫,他關(guān)閉了對(duì)SNAPSHOT的支持,以防止引入SNAPSHOT版本的插件而導(dǎo)致不穩(wěn)定的構(gòu)建。
一般來說,中央倉庫所包含的插件完全能夠滿足我們的需要,因此也不需要配置其他的插件倉庫。只有在很少的情況下,項(xiàng)目使用的插件無法在中央倉庫找到,或者自己編寫了插件,這個(gè)時(shí)候可以參考上述的配置,在POM或者settings.xml中加入其他的插件倉庫配置。
插件的默認(rèn)groupId
在POM中配置插件的時(shí)候,如果該插件是Maven的官方插件(即如果其groupId為org.apache.maven.plugins),就可以省略groupId配置,見下面所示。
<build><plugins><artifactId>maven-compiler-plugin</artifactId><version>2.1</version><configuration><source>1.5</source><target>1.5</target></configuration></plugins></build>?
上述配置中省略了maven-compiler-plugin的groupId,Maven在解析該插件的時(shí)候,會(huì)自動(dòng)用默認(rèn)groupId org.apache.maven.plugins補(bǔ)齊。
不推薦使用Maven的這一機(jī)制,雖然這么做可以省略一些配置,但這樣的配置會(huì)讓團(tuán)隊(duì)中不熟悉Maven的成員感到費(fèi)解,況且能省略的配置也就僅僅一行而已。
解析插件版本
同樣是為了簡化插件的配置和使用,在用戶沒有提供插件版本的情況下,Maven會(huì)自動(dòng)解析插件版本。
首先,Maven在超級(jí)POM中為所有核心插件設(shè)定了版本,超級(jí)POM是所有Maven項(xiàng)目的父POM,所有項(xiàng)目都繼承這個(gè)超級(jí)POM的配置,因此,即使用戶不加任何配置,Maven使用核心插件的時(shí)候,他們的版本就已經(jīng)確定了。這些插件包括maven-clean-plugin、maven-compiler-plugin、maven-surefire-plugin等。
如果用戶使用某個(gè)插件時(shí)沒有設(shè)定版本,而這個(gè)插件又不屬于核心插件的范疇,Maven就會(huì)去檢查所有倉庫中可用的版本,然后做出選擇。以maven-compiler-plugin為例,他在中央倉庫的倉庫元數(shù)據(jù)為http://repol.maven.org/maven2/org/apache/maven/plugins/maven-compiler/maven-metadata.xml,其內(nèi)容如下所示。
<?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.1</version><version>2.0.2</version><version>2.1</version></versions></versioning> </metadata>Maven遍歷本地倉庫和所有遠(yuǎn)程插件倉庫,將該路徑下的倉庫元數(shù)據(jù)歸并后,就能計(jì)算出latest和release的值。latest表示所有倉庫中該構(gòu)件的最新版本,而release表示最新的非快照版本。在Maven 2中,插件的版本會(huì)被解析至latest。也就是說,當(dāng)用戶使用某個(gè)非核心插件且沒有聲明版本的時(shí)候,Maven會(huì)將版本解析為所有可用倉庫中的最新版本,而這個(gè)版本也可能是快照版。
當(dāng)插件的版本為快照版本時(shí),就會(huì)出現(xiàn)潛在的問題。Maven會(huì)基于更新策略,檢查并使用快照的更新。某個(gè)插件可能昨天還用的好好的,今天就出錯(cuò)了,其原因就是這個(gè)快照版本的插件發(fā)生了變化。為了防止這類問題,Maven 3調(diào)整了解析機(jī)制,當(dāng)插件沒有聲明版本的時(shí)候,不再解析至latest,而是使用release。這樣就可以避免由于快照頻繁更新而導(dǎo)致的插件行為不穩(wěn)定。
依賴Maven解析插件版本其實(shí)是不推薦的做法,即使Maven 3 將版本解析到最新的非快照版,也還是會(huì)有潛在的不穩(wěn)定性。例如,可能某個(gè)插件發(fā)布了一個(gè)新的版本,而這個(gè)版本的行為與之前的版本發(fā)生了變化,這種變化就可能導(dǎo)致項(xiàng)目構(gòu)件失敗。因此,使用插件的時(shí)候,應(yīng)該一直顯式的設(shè)定版本,這也解釋了Maven為什么要在超級(jí)POM中為核心插件設(shè)定版本。
解析插件前綴
現(xiàn)在解釋Maven如何根據(jù)插件前綴解析得到插件坐標(biāo)。
插件前綴與groupId:artifactId是一一對(duì)應(yīng)的,這種匹配關(guān)系存儲(chǔ)在倉庫元數(shù)據(jù)中。與groupId/artifactId/maven-metadata.xml不同,這里的倉庫元數(shù)據(jù)為groupId/maven-metadata.xml,那么這里的groupId是什么呢?主要的插件都位于http://repol.maven.org/maven2/org/apache/maven/plugins和http://repository.codehaus.org/org/codehaus/mojo/,相應(yīng)地,Maven在解析插件倉庫元數(shù)據(jù)的時(shí)候,會(huì)默認(rèn)使用org.apache.maven.plugins和org.codehaus.mojo兩個(gè)groupId。也可以通過配置settings.xml讓Maven檢查其他groupId上的插件倉庫元數(shù)據(jù):
<settings><pluginGroups><pluginGroup>com.your.plugins</pluginGroup></pluginGroups> </settings>基于該配置,Maven就不僅僅會(huì)檢查org/apache/maven/plugins/maven-metadata.xml和org/codehaus/mojo/maven-metadata.xml,還會(huì)檢查com/your/plugins/maven-metadata.xml。
下面看一下插件倉庫元數(shù)據(jù)的內(nèi)容,見下面。
<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>上述內(nèi)容是從中央倉庫的org.apache.maven.plugins.groupId下插件倉庫元數(shù)據(jù)中截取的一些片段,從這段數(shù)據(jù)中就能看到maven-clean-plugin的前綴為clean,maven-compiler-plugin的前綴為compiler,maven-dependency-plugin的前綴為dependency。
當(dāng)Maven解析到dependency:tree這樣的命令后,他首先基于默認(rèn)的groupId歸并所有插件倉庫的元數(shù)據(jù)org/apache/plugins/maven-metadata.xml;其次檢查歸并后的元數(shù)據(jù),找到對(duì)應(yīng)的artifactId為maven-dependency-plugin;然后結(jié)合當(dāng)前元數(shù)據(jù)的groupId為org.apache.maven.plugins;最后解析得到version,這時(shí)就得到了完整的插件坐標(biāo)。如果org/apache/maven/plugins/maven-metadata.xml,以及用戶自定義的插件組。如果所有元數(shù)據(jù)中都不包含該前綴,則報(bào)錯(cuò)。
?
參考:
maven plugins 參考:http://maven.apache.org/plugins/index.html
?
?
總結(jié)
以上是生活随笔為你收集整理的Maven(2)--生命周期以及插件目标的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: 架构师知识地图
- 下一篇: Maven(3)--聚合与继承
