作者:George Ma
第一篇文章大概的介紹了一下Apache Maven以及它的下載和安裝,并且運(yùn)行了一個(gè)簡(jiǎn)單的示例逛裤。那么在對(duì)maven有了一點(diǎn)接觸后,接下去的一步是要了解maven的核心概念帮坚,這樣才能在使用maven的時(shí)候游刃有余踩身。
接下來我們介紹下面這幾個(gè)核心概念:
POM (Project Object Model)
Maven 插件
Maven 生命周期
Maven 依賴管理
Maven 庫(kù)
POM (Project Object Model)
一個(gè)項(xiàng)目所有的配置都放置在 POM 文件中:定義項(xiàng)目的類型、名字吐句,管理依賴關(guān)系胁后,定制插件的行為等等。比如說嗦枢,你可以配置 compiler 插件讓它使用 java 1.5 來編譯攀芯。
現(xiàn)在看一下第一篇文章中示例的 POM
Xml 代碼
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.mycompany.helloworld</groupId> <artifactId>helloworld</artifactId> <version>1.0-SNAPSHOT</version> <packaging>jar</packaging> <name>helloworld</name> <url>http://maven.apache.org</url> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> <scope>test</scope> </dependency> </dependencies> </project>
在 POM 中,groupId, artifactId, packaging, version 叫作 maven 坐標(biāo)文虏,它能唯一的確定一個(gè)項(xiàng)目侣诺。有了 maven 坐標(biāo),我們就可以用它來指定我們的項(xiàng)目所依賴的其他項(xiàng)目氧秘,插件年鸳,或者父項(xiàng)目。一般 maven 坐標(biāo)寫成如下的格式:
groupId:artifactId:packaging:version
像我們的例子就會(huì)寫成:
com.mycompany.helloworld: helloworld: jar: 1.0-SNAPSHOT
我們的 helloworld 示例很簡(jiǎn)單丸相,但是大項(xiàng)目一般會(huì)分成幾個(gè)子項(xiàng)目搔确。在這種情況下,每個(gè)子項(xiàng)目就會(huì)有自己的 POM 文件,然后它們會(huì)有一個(gè)共同的父項(xiàng)目妥箕。這樣只要構(gòu)建父項(xiàng)目就能夠構(gòu)建所有的子項(xiàng)目了滥酥。子項(xiàng)目的 POM 會(huì)繼承父項(xiàng)目的 POM。另外畦幢,所有的 POM都繼承了一個(gè) Super-POM坎吻。Super-POM 設(shè)置了一些默認(rèn)值,比如在第一篇文章中提到的默認(rèn)的目錄結(jié)構(gòu)宇葱,默認(rèn)的插件等等瘦真,它遵循了慣例優(yōu)于配置的原則。所以盡管我們的這個(gè) POM 很簡(jiǎn)單黍瞧,但是這只是你看得見的一部分诸尽。運(yùn)行時(shí)候的 POM 要復(fù)雜的多。 如果你想看到運(yùn)行時(shí)候的 POM 的全部?jī)?nèi)容的話印颤,可以運(yùn)行下面的命令:
$mvn help:effective-pom
Maven 插件
在第一篇文章中您机,我們用了 mvn archetype:generate 命令來生成一個(gè)項(xiàng)目。那么這里的 archetype:generate 是什么意思呢年局?archetype 是一個(gè)插件的名字际看,generate是目標(biāo)(goal)的名字。這個(gè)命令的意思是告訴 maven 執(zhí)行 archetype 插件的 generate 目標(biāo)矢否。插件目標(biāo)通常會(huì)寫成pluginId:goalId
一個(gè)目標(biāo)是一個(gè)工作單元仲闽,而插件則是一個(gè)或者多個(gè)目標(biāo)的集合。比如說Jar插件僵朗,Compiler插件赖欣,Surefire插件等。從看名字就能知道验庙,Jar 插件包含建立Jar文件的目標(biāo)顶吮, Compiler 插件包含編譯源代碼和單元測(cè)試代碼的目標(biāo)。Surefire 插件的話壶谒,則是運(yùn)行單元測(cè)試云矫。
看到這里,估計(jì)你能明白了汗菜,mvn 本身不會(huì)做太多的事情让禀,它不知道怎么樣編譯或者怎么樣打包。它把構(gòu)建的任務(wù)交給插件去做陨界。插件定義了常用的構(gòu)建邏輯巡揍,能夠被重復(fù)利用。這樣做的好處是菌瘪,一旦插件有了更新腮敌,那么所有的 maven 用戶都能得到更新阱当。
Maven 生命周期
在上一篇文章中,我們用的第二個(gè)命令是:mvn package糜工。這里的 package 是一個(gè)maven的生命周期階段 (lifecycle phase )弊添。生命周期指項(xiàng)目的構(gòu)建過程,它包含了一系列的有序的階段 (phase)捌木,而一個(gè)階段就是構(gòu)建過程中的一個(gè)步驟油坝。
那么生命周期階段和上面說的插件目標(biāo)之間是什么關(guān)系呢?插件目標(biāo)可以綁定到生命周期階段上刨裆。一個(gè)生命周期階段可以綁定多個(gè)插件目標(biāo)澈圈。當(dāng) maven 在構(gòu)建過程中逐步的通過每個(gè)階段時(shí),會(huì)執(zhí)行該階段所有的插件目標(biāo)帆啃。
maven 能支持不同的生命周期瞬女,但是最常用的是默認(rèn)的Maven生命周期 (default Maven lifecycle )。如果你沒有對(duì)它進(jìn)行任何的插件配置或者定制的話努潘,那么上面的命令 mvn package 會(huì)依次執(zhí)行默認(rèn)生命周期中直到包括 package 階段前的所有階段的插件目標(biāo):
process-resources 階段:resources:resources
compile 階段:compiler:compile
process-classes 階段:(默認(rèn)無(wú)目標(biāo))
process-test-resources 階段:resources:testResources
test-compile 階段:compiler:testCompile
test 階段:surefire:test
prepare-package 階段:(默認(rèn)無(wú)目標(biāo))
package 階段:jar:jar
Maven 依賴管理
之前我們說過诽偷,maven 坐標(biāo)能夠確定一個(gè)項(xiàng)目。換句話說慈俯,我們可以用它來解決依賴關(guān)系渤刃。在 POM 中,依賴關(guān)系是在 dependencies 部分中定義的贴膘。在上面的 POM 例子中,我們用 dependencies 定義了對(duì)于 junit 的依賴:
Xml 代碼
<dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> <scope>test</scope> </dependency> </dependencies>
那這個(gè)例子很簡(jiǎn)單略号,但是實(shí)際開發(fā)中我們會(huì)有復(fù)雜得多的依賴關(guān)系刑峡,因?yàn)楸灰蕾嚨?jar 文件會(huì)有自己的依賴關(guān)系。那么我們是不是需要把那些間接依賴的 jar 文件也都定義在POM中呢玄柠?答案是不需要突梦,因?yàn)?maven 提供了傳遞依賴的特性。
所謂傳遞依賴是指 maven 會(huì)檢查被依賴的 jar 文件羽利,把它的依賴關(guān)系納入最終解決的依賴關(guān)系鏈中宫患。針對(duì)上面的 junit 依賴關(guān)系,如果你看一下 maven 的本地庫(kù)(我們馬上會(huì)解釋 maven 庫(kù))~/.m2/repository/junit/junit/3.8.1/ 这弧,[圖片上傳中娃闲。。匾浪。(1)]
你會(huì)發(fā)現(xiàn) maven 不但下載了 junit-3.8.1.jar皇帮,還下載了它的 POM 文件。這樣 maven 就能檢查 junit 的依賴關(guān)系蛋辈,把它所需要的依賴也包括進(jìn)來属拾。
在 POM 的 dependencies 部分中,scope 決定了依賴關(guān)系的適用范圍。我們的例子中 junit 的 scope 是 test渐白,那么它只會(huì)在執(zhí)行 compiler:testCompile and surefire:test 目標(biāo)的時(shí)候才會(huì)被加到 classpath 中尊浓,在執(zhí)行 compiler:compile 目標(biāo)時(shí)是拿不到 junit 的。
我們還可以指定 scope 為 provided纯衍,意思是 JDK 或者容器會(huì)提供所需的jar文件栋齿。比如說在做web應(yīng)用開發(fā)的時(shí)候,我們?cè)诰幾g的時(shí)候需要 servlet API jar 文件托酸,但是在打包的時(shí)候不需要把這個(gè) jar 文件打在 WAR 中褒颈,因?yàn)閟ervlet容器或者應(yīng)用服務(wù)器會(huì)提供的。
scope 的默認(rèn)值是 compile励堡,即任何時(shí)候都會(huì)被包含在 classpath 中谷丸,在打包的時(shí)候也會(huì)被包括進(jìn)去。
Maven 庫(kù)
當(dāng)?shù)谝淮芜\(yùn)行 maven 命令的時(shí)候应结,你需要 Internet 連接刨疼,因?yàn)樗獜木W(wǎng)上下載一些文件。那么它從哪里下載呢鹅龄?它是從 maven 默認(rèn)的遠(yuǎn)程庫(kù)(http://repo1.maven.org/maven2) 下載的揩慕。這個(gè)遠(yuǎn)程庫(kù)有 maven 的核心插件和可供下載的 jar 文件。
但是不是所有的 jar 文件都是可以從默認(rèn)的遠(yuǎn)程庫(kù)下載的扮休,比如說我們自己開發(fā)的項(xiàng)目迎卤。這個(gè)時(shí)候,有兩個(gè)選擇:要么在公司內(nèi)部設(shè)置定制庫(kù)玷坠,要么手動(dòng)下載和安裝所需的jar文件到本地庫(kù)蜗搔。
本地庫(kù)是指 maven 下載了插件或者 jar 文件后存放在本地機(jī)器上的拷貝。在 Linux 上八堡,它的位置在 ~/.m2/repository樟凄,在 Windows XP 上,在 C:\Documents and Settings\username.m2\repository 兄渺,在 Windows 7 上缝龄,在 C:\Users\username.m2\repository。當(dāng) maven 查找需要的 jar 文件時(shí)挂谍,它會(huì)先在本地庫(kù)中尋找叔壤,只有在找不到的情況下,才會(huì)去遠(yuǎn)程庫(kù)中找凳兵。
運(yùn)行下面的命令能把我們的 helloworld 項(xiàng)目安裝到本地庫(kù):
$mvn install
一旦一個(gè)項(xiàng)目被安裝到了本地庫(kù)后百新,你別的項(xiàng)目就可以通過 maven 坐標(biāo)和這個(gè)項(xiàng)目建立依賴關(guān)系。比如如果我現(xiàn)在有一個(gè)新項(xiàng)目需要用到 helloworld庐扫,那么在運(yùn)行了上面的 mvn install 命令后饭望,我就可以如下所示來建立依賴關(guān)系:
Xml 代碼
<dependency> <groupId>com.mycompany.helloworld</groupId> <artifactId>helloworld</artifactId> <version>1.0-SNAPSHOT</version> </dependency>
好了仗哨,maven 的核心概念就簡(jiǎn)單的介紹到這里。至于在 Eclipse 中如何使用 maven铅辞,這個(gè)網(wǎng)上很多了厌漂,google 一下就行。