maven內(nèi)部運(yùn)行原理解析(一)

maven至今還是Java編程語(yǔ)言構(gòu)建的事實(shí)標(biāo)準(zhǔn),大部分項(xiàng)目還在使用maven來(lái)進(jìn)行構(gòu)建敷鸦,因此了解maven內(nèi)部運(yùn)行的原理對(duì)定位和分析問(wèn)題還是很有裨益的。本篇文章主要介紹一些maven內(nèi)部運(yùn)行過(guò)程中的一些基本概念,相信看完后急鳄,對(duì)那么些剛剛接觸maven的讀者來(lái)說(shuō)maven將不再陌生谤民。
??在具體分析項(xiàng)目構(gòu)建的過(guò)程前,需要了解maven的一些基本概念疾宏,這些概念十分重要张足,請(qǐng)務(wù)必理解清楚后再看下文】裁辏基本概念主要有:POM为牍,Lifecycle。這兩個(gè)概念又會(huì)包含一些小的概念岩馍,下文會(huì)逐步講解碉咆。
??POM: 注意這里的POM不是maven中構(gòu)建過(guò)程使用的配置文件pom.xml,但他們之間還是有聯(lián)系的蛀恩。POM的全稱是Project Object Model吟逝,用通俗點(diǎn)的話說(shuō)就是對(duì)要構(gòu)建的項(xiàng)目進(jìn)行建模,將要構(gòu)建的項(xiàng)目看成是一個(gè)對(duì)象(Object)赦肋,后文就使用PO來(lái)指代這個(gè)對(duì)象块攒。既然是一個(gè)對(duì)象,那么PO有哪些屬性呢佃乘?在maven中一個(gè)項(xiàng)目都是用一個(gè)唯一的坐標(biāo)(coordinate)來(lái)表示囱井,坐標(biāo)由groupId, artifactId, version, classifier, type這五部分組成。這樣來(lái)說(shuō)PO應(yīng)該也要具備坐標(biāo)屬性趣避。另外一方面庞呕,一個(gè)項(xiàng)目肯定不是孤立存在的,可能依賴于其他的一些項(xiàng)目程帕,那么也就是說(shuō)PO應(yīng)該具備dependencies這個(gè)屬性住练,用來(lái)表示其所依賴的外部項(xiàng)目。我們可以嘗試一下用Java代碼來(lái)描述下PO這個(gè)對(duì)象:

class PO{
    private String groupId;
    private String artifactId;
    private String version;
    private String classifier;
    private String type;
    private Set<PO> dependencies;
}

我們知道XML的表達(dá)能力是很強(qiáng)大的愁拭,一個(gè)Java中的對(duì)象是可以用XML來(lái)描述讲逛,例如一個(gè)上面定義的PO對(duì)象則可以用下面的XML來(lái)描述(表達(dá)有不規(guī)范之處,理解其中的含義即可):

<PO>
    <groupId></groupId>
    <artifactId></artifactId>
    <version></version>
    <classifier><classifier>
    <type></type>
    <dependencies>
        <PO></PO>
        <PO></PO>
        ...
    </dependencies>
</PO>

是不是好像和什么有點(diǎn)類似岭埠?對(duì)盏混,就是pom.xml。pom.xml就是PO對(duì)象的XML描述惜论。上面的PO定義還不完整许赃,我們繼續(xù)看下PO還有什么其他的屬性。我們知道在Java中類是可以繼承的馆类,一個(gè)對(duì)象在創(chuàng)建的時(shí)候會(huì)同時(shí)創(chuàng)建其父類對(duì)象混聊,類似的,PO對(duì)象也有其父對(duì)象乾巧,用parent屬性來(lái)表示句喜,并且PO對(duì)象會(huì)繼承其父對(duì)象的所有屬性僵闯。另外一方面,一個(gè)項(xiàng)目可能根據(jù)不同職責(zé)分為多個(gè)模塊(module)藤滥,所有模塊其實(shí)也就是一個(gè)單獨(dú)的項(xiàng)目鳖粟,只不過(guò)這些項(xiàng)目會(huì)使用其父對(duì)象的一些屬性來(lái)進(jìn)行構(gòu)建。我們將這些新的屬性加到PO的定義中去:

class PO{
    private String groupId;
    private String artifactId;
    private String version;
    private String classifier;
    private String type;
    private Set<PO> dependencies;
    private PO parent;
    private Set<PO> modules;
}

再將這個(gè)定義用XML語(yǔ)言表示一下:

<PO>
    <parent></parent>
    <groupId></groupId>
    <artifactId></artifactId>
    <version></version>
    <classifier><classifier>
    <type></type>
    <dependencies>
        <PO></PO>
        <PO></PO>
        ...
    </dependencies>
    <modules>
        ...
    </modules>
</PO>

是不是越來(lái)越像pom.xml了拙绊?對(duì)向图,這就是pom.xml的由來(lái)。再說(shuō)一遍:pom.xml就是PO對(duì)象的XML描述标沪。到此為止榄攀,相信你再看pom.xml文件時(shí),會(huì)有一個(gè)全新的認(rèn)識(shí)金句。

上面說(shuō)的這些PO屬性是項(xiàng)目的一些固有屬性檩赢,到目前為止,我們還沒(méi)有涉及項(xiàng)目的構(gòu)建過(guò)程违寞。構(gòu)建過(guò)程對(duì)應(yīng)的是PO對(duì)象的build屬性贞瞒,那么你應(yīng)該馬上想到,在pom.xml中就是<build>元素中的內(nèi)容趁曼。這里就有引入maven中第二個(gè)核心概念:Lifecycle军浆。Lifecycle直譯過(guò)來(lái)就是生命周期。我們平常會(huì)接觸到哪些周期呢挡闰?一年中春夏秋冬就是一個(gè)周期乒融。一個(gè)周期中可能分為多個(gè)階段,比如這里的春夏秋冬摄悯。在maven中一個(gè)構(gòu)建過(guò)程就對(duì)應(yīng)一個(gè)Lifecycle赞季,這個(gè)Lifecycle也分為多個(gè)階段,每個(gè)階段叫做phase奢驯。你可能會(huì)問(wèn)申钩,那這個(gè)Lifecycle中包含多少個(gè)phase呢?一個(gè)標(biāo)準(zhǔn)的構(gòu)建Lifecycle包含了如下的phase:

validate: 用于驗(yàn)證項(xiàng)目的有效性和其項(xiàng)目所需要的內(nèi)容是否具備
initialize:初始化操作叨橱,比如創(chuàng)建一些構(gòu)建所需要的目錄等典蜕。
generate-sources:用于生成一些源代碼,這些源代碼在compile phase中需要使用到
process-sources:對(duì)源代碼進(jìn)行一些操作罗洗,例如過(guò)濾一些源代碼
generate-resources:生成資源文件(這些文件將被包含在最后的輸入文件中)
process-resources:對(duì)資源文件進(jìn)行處理
compile:對(duì)源代碼進(jìn)行編譯
process-classes:對(duì)編譯生成的文件進(jìn)行處理
generate-test-sources:生成測(cè)試用的源代碼
process-test-sources:對(duì)生成的測(cè)試源代碼進(jìn)行處理
generate-test-resources:生成測(cè)試用的資源文件
process-test-resources:對(duì)測(cè)試用的資源文件進(jìn)行處理
test-compile:對(duì)測(cè)試用的源代碼進(jìn)行編譯
process-test-classes:對(duì)測(cè)試源代碼編譯后的文件進(jìn)行處理
test:進(jìn)行單元測(cè)試
prepare-package:打包前置操作
package:打包
pre-integration-test:集成測(cè)試前置操作   
integration-test:集成測(cè)試
post-integration-test:集成測(cè)試后置操作
install:將打包產(chǎn)物安裝到本地maven倉(cāng)庫(kù)
deploy:將打包產(chǎn)物安裝到遠(yuǎn)程倉(cāng)庫(kù)

在maven中,你執(zhí)行任何一個(gè)phase時(shí)钢猛,maven會(huì)將其之前的phase都執(zhí)行伙菜。例如 mvn install,那么maven會(huì)將deploy之外的所有phase按照他們出現(xiàn)的順序一次執(zhí)行命迈。
??Lifecycle還牽涉到另外一個(gè)非常重要的概念:goal贩绕。注意上面Lifecycle的定義火的,也就是說(shuō)maven為程序的構(gòu)建定義了一套規(guī)范流程:第一步需要validate,第二步需要initialize... ... compile淑倾,test馏鹤,package,... ... install娇哆,deploy湃累,但是并沒(méi)有定義每一個(gè)phase具體應(yīng)該如何操作。這里的phase的作用有點(diǎn)類似于Java語(yǔ)言中的接口碍讨,只協(xié)商了一個(gè)契約治力,但并沒(méi)有定義具體的動(dòng)作。比如說(shuō)compile這個(gè)phase定義了在構(gòu)建流程中需要經(jīng)過(guò)編譯這個(gè)階段勃黍,但沒(méi)有定義應(yīng)該怎么編譯(編譯的輸入是什么宵统?用什么編譯javac/gcc?)。這里具體的動(dòng)作就是由goal來(lái)定義覆获,一個(gè)goal在maven中就是一個(gè)Mojo(Maven old java object)马澈。Mojo抽象類中定義了一個(gè)execute()方法,一個(gè)goal的具體動(dòng)作就是在execute()方法中實(shí)現(xiàn)弄息。實(shí)現(xiàn)的Mojo類應(yīng)該放在哪里呢箭券?答案是maven plugin里,所謂的plugin其實(shí)也就是一個(gè)maven項(xiàng)目疑枯,只不過(guò)這個(gè)項(xiàng)目會(huì)引用maven的一些API辩块,plugin項(xiàng)目也具備maven坐標(biāo)。
??在執(zhí)行具體的構(gòu)建時(shí)荆永,我們需要為lifecycle的每個(gè)phase都綁定一個(gè)goal废亭,這樣才能夠在每個(gè)步驟執(zhí)行一些具體的動(dòng)作。比如在lifecycle中有個(gè)compile phase規(guī)定了構(gòu)建的流程需要經(jīng)過(guò)編譯這個(gè)步驟具钥,而maven-compile-plugin這個(gè)plugin有個(gè)compile goal就是用javac來(lái)將源文件編譯為class文件的豆村,我們需要做的就是將compile這個(gè)phase和maven-compile-plugin中的compile這個(gè)goal進(jìn)行綁定,這樣就可以實(shí)現(xiàn)Java源代碼的編譯了骂删。有點(diǎn)繞掌动,多看幾遍。那么有人就會(huì)問(wèn)宁玫,在哪里綁定呢粗恢?答案是在pom.xml<build>元素中配置即可。例如:

<build>
<plugins>
  <plugin>
    <artifactId>maven-myquery-plugin</artifactId>
    <version>1.0</version>
    <executions>
      <execution>
        <id>execution1</id>
        <phase>test</phase>
        <configuration>
          <url>http://www.foo.com/query</url>
          <timeout>10</timeout>
          <options>
            <option>one</option>
            <option>two</option>
            <option>three</option>
          </options>
        </configuration>
        <goals>
          <goal>query</goal>
        </goals>
      </execution>
    </executions>
  </plugin>
</plugins>
</build>

就將maven-myquery-plugin中的query這個(gè)goal綁定到了test這個(gè)phase欧瘪,后續(xù)在maven執(zhí)行到test phase時(shí)就會(huì)執(zhí)行query goal眷射。還有有人可能會(huì)問(wèn),我都沒(méi)有指定Java源文件的位置,編譯啥妖碉?這就引出了maven的design principle涌庭。在maven中,有一個(gè)非常著名的principle就是convention over configuration(約定優(yōu)于配置)欧宜。這一點(diǎn)和ant有非常大的區(qū)別坐榆,例如使用ant來(lái)進(jìn)行編譯時(shí),我們需要指定源文件的位置冗茸,輸出文件的位置席镀,javac的位置,classpath... ...在maven中這些都是不需要蚀狰,若沒(méi)有手動(dòng)配置愉昆,maven默認(rèn)從<項(xiàng)目根目錄>/src/main/java這個(gè)目錄去查找Java源文件,編譯后的class文件會(huì)保存在<項(xiàng)目根目錄>/target/classes目錄麻蹋。在maven中跛溉,所有的PO都有一個(gè)根對(duì)象,就是Super POM扮授。Super POM中定義了所有的默認(rèn)的配置項(xiàng)芳室。Super POM對(duì)應(yīng)的pom.xml文件可以在maven安裝目錄下lib/maven-model-builder-3.0.3.jar:org/apache/maven/model/pom-4.0.0.xml中找到。用一張圖來(lái)表示maven Lifecycle刹勃,phase堪侯,goal之間的關(guān)系:


Lifecyle-phase-plugin-goal關(guān)系圖

到此為止,相信對(duì)于POM, pom.xml荔仁,Lifecycle伍宦, phase, goal這些概念應(yīng)該十分清楚了。還有疑問(wèn)乏梁?請(qǐng)留言次洼。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市遇骑,隨后出現(xiàn)的幾起案子卖毁,更是在濱河造成了極大的恐慌,老刑警劉巖落萎,帶你破解...
    沈念sama閱讀 218,858評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件亥啦,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡练链,警方通過(guò)查閱死者的電腦和手機(jī)翔脱,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,372評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)兑宇,“玉大人碍侦,你說(shuō)我怎么就攤上這事粱坤×ジ猓” “怎么了瓷产?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,282評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)枚驻。 經(jīng)常有香客問(wèn)我濒旦,道長(zhǎng),這世上最難降的妖魔是什么再登? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,842評(píng)論 1 295
  • 正文 為了忘掉前任尔邓,我火速辦了婚禮,結(jié)果婚禮上锉矢,老公的妹妹穿的比我還像新娘梯嗽。我一直安慰自己,他們只是感情好沽损,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,857評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布灯节。 她就那樣靜靜地躺著,像睡著了一般绵估。 火紅的嫁衣襯著肌膚如雪炎疆。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,679評(píng)論 1 305
  • 那天国裳,我揣著相機(jī)與錄音形入,去河邊找鬼。 笑死缝左,一個(gè)胖子當(dāng)著我的面吹牛亿遂,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播渺杉,決...
    沈念sama閱讀 40,406評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼蛇数,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了少办?” 一聲冷哼從身側(cè)響起苞慢,我...
    開(kāi)封第一講書(shū)人閱讀 39,311評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎英妓,沒(méi)想到半個(gè)月后挽放,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,767評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡蔓纠,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評(píng)論 3 336
  • 正文 我和宋清朗相戀三年辑畦,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片腿倚。...
    茶點(diǎn)故事閱讀 40,090評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡纯出,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情暂筝,我是刑警寧澤箩言,帶...
    沈念sama閱讀 35,785評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站焕襟,受9級(jí)特大地震影響陨收,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜鸵赖,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,420評(píng)論 3 331
  • 文/蒙蒙 一务漩、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧它褪,春花似錦饵骨、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,988評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至包吝,卻和暖如春饼煞,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背诗越。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,101評(píng)論 1 271
  • 我被黑心中介騙來(lái)泰國(guó)打工砖瞧, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人嚷狞。 一個(gè)月前我還...
    沈念sama閱讀 48,298評(píng)論 3 372
  • 正文 我出身青樓块促,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親床未。 傳聞我的和親對(duì)象是個(gè)殘疾皇子竭翠,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,033評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容