我們看一個(gè)最常見到的例子:
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.mycompany.app</groupId>
<artifactId>my-app</artifactId>
<packaging>jar</packaging>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
?
該例子表示你的project有一個(gè)junit dependency。你可能會問:這個(gè)dependency從哪里來?junit jar在哪里?
?
A dependency
是對
repository
里的某個(gè)
artifact
的引用。
POM
定義了一個(gè)
dependency
,執(zhí)行的時(shí)候就會根據(jù)
dependency
的
groupId, artifactId and version
,來
search it from repository
。
你根本不需要在
pom.xml
里指明該
dependancy
來自哪個(gè)
repository
,
maven
會先查找
local repository
,如果
local repository
存在該
dependancy
引用的
artifact
,就使用它,如果不存在,則搜索所有你設(shè)置的
remote repository
,如果找到它,就把它
download
到
local repository
。
缺省狀態(tài)下,通常都是從central maven repository(
http://www.ibiblio.org/maven2
)來download artifact。
如果你的
pom.xml
定義了多個(gè)
remote repository
,那么就按順序依次試圖從
remote repository
下載
.
?
例如上面的例子,maven會先check local repository看是否有想要的junit artifact,如果沒有,則從remote repository download到local repository。這時(shí),local repository里artifact目錄結(jié)構(gòu)包含:
?
?
下圖是在repository里所有artifact通用的目錄結(jié)構(gòu):
?
?
groupId是fully qualified domain name,例如為x.y.z,則結(jié)構(gòu)為:
?
?
maven
是如何根據(jù)定義的
dependancy
來從
repository
里查找呢?例如上例,就會根據(jù)
groupId?“junit”, artifactId “junit”, and version
“
3.8.1”
,在
repository
里查找
~/.m2/repository/junit/junit/3.8.1/junit-3.8.1.jar
。
?
?
dependancy
功能是
maven
最強(qiáng)大的功能和最顯著的優(yōu)勢。以前
maven
沒出現(xiàn)之前,通常的
project
都會把要用到的
jar files
都放在
project subdirectory
下,或開發(fā)一個(gè)
web app
,你要把
10
多個(gè)
jar
添加到
classpath
,并把它們放到
lib
目錄下。這樣如果你開發(fā)
100
個(gè)類似的
web app
,你的每一個(gè)
web app
開發(fā)目錄下面都會包含有這些
jar files
。這樣如果某個(gè)
jar
的版本出現(xiàn)更新,就會要更新
100
個(gè)
project
里的
jar
。而使用
maven
,就會大大減輕你的工作量。
?
例如,你有100個(gè)web app都使用了spring 1.2.6 framework,如果你使用maven,你不需要存儲所有的spring jars到各個(gè)project里,你只需要在POM.XML里定義一個(gè)spring dependancy,那么如果升級到spring 2.0,只需要把pom.xml里dependancy的<version>修改為2.0即可。
Dependency機(jī)制介紹
?
Dependency
機(jī)制的三個(gè)知識點(diǎn)
-
Transitive Dependencies
-
Dependency Scope
-
Dependency Management
Transitive Dependencies
(可傳遞的依賴)
這是maven 2.0的新特征。
它使你不需要指定
dependency
的位置而自動(dòng)定位。而且可傳遞的依賴就是說依賴能夠自動(dòng)繼承和傳遞,例如
project A
依賴
project B
的
artifact
,而
project B
則依賴
project C
的
artifact
,那么在
build project A
時(shí),就會使用到所有
project
、子
project
的依賴。
?
一個(gè)project的
依賴的總個(gè)數(shù)沒有限制,但是如果出現(xiàn)死循環(huán)依賴則會出現(xiàn)問題。
?
由于依賴可以傳遞,因此有可能一個(gè)project要依賴的東東會很多,因此可以通過下列幾種方式來限制要包括的dependency:
-
Dependency mediation
–
意思是
強(qiáng)烈建議顯式設(shè)置你使用的
dependency
的版本號,因?yàn)?
dependency
可能會有多種版本。目前
Maven 2.0
支持
"nearest definition"
(見下面的解釋)。
注意:如果在
dependency tree
的同一個(gè)
depth
里定義了同一個(gè)
dependency
的
2
個(gè)版本,那么使用先定義的那個(gè)版本
。
-
"nearest definition"
表示在
dependencies tree
里最靠近你的
project
的版本。例如,如果
project A
的依賴性為:
A -> B -> C -> D 2.0
和
A -> E -> D 1.0,
那么
D
的
1.0
版本將會被使用。因?yàn)閺?
A
通過
E
到達(dá)
D
的路徑是最短的。如果本例你硬是想要使用
D 2.0
,那么你可以在
A
里定義一個(gè)
D
的
dependency
。
?
-
Dependency management
–
表示
maven
允許你在你的
pom.xml
里設(shè)置你要使用的
depedency
的版本號,即使這個(gè)
depedency
你可能不知道是從哪里來的可傳遞依賴,也不知道該依賴定義的版本是什么,你都可以根據(jù)“
nearest definition
”法則來在你的
pom.xml
里設(shè)置版本號。
例如上面的例子,你可以直接在
A
里設(shè)置對
D
的依賴(設(shè)置版本號),即使
A
并不直接使用
D
。
?
-
Dependency scope
–
盡量為要包含的
dependencies
設(shè)置要用到它的
scope
。
下面會詳細(xì)解釋
?
?
Dependency Scope
Dependency scope
是設(shè)置什么
stage
要使用它,用來限制依賴的傳遞。
?
總共有5種Scopes:
-
compile
–
這是缺省
scope
,表明是所有任務(wù)所需的資源。“
Compile
”
dependencies are available in all classpaths.
-
provided
–
表示該
dependency
是
JDK
部分或應(yīng)用服務(wù)器的
classpath
里已經(jīng)自帶的資源,
例如
EJB
的
dependency jars
,只需要在
compile
時(shí)使用,在例如打包時(shí)就不應(yīng)該把它打包進(jìn)
jar, war or ear
里,因?yàn)?
JDK or APP SERVER
里本身就有。
-
runtime
- this scope indicates that the dependency
is not required for compilation, but is for execution
. It
is in the runtime and test classpaths, but not the compile classpath.
-
test
–
表示該
dependency
只會在
test compilation and execution phases
使用。
例如在使用
junit
依賴
時(shí),
scope
參數(shù)的值為
test
來告訴
Maven
這個(gè)依賴項(xiàng)只是在測試階段所需的,而不是運(yùn)行時(shí)所需的資源。
-
system
- this scope is similar to provided except that you have to provide the JAR which contains it explicitly. The artifact is always available and is not looked up in a repository.
后面會詳細(xì)講解
不同的
scope
會影響“依賴的依賴”的
scope
。下表列出的就是當(dāng)一個(gè)“依賴”的scope設(shè)置為最左一列的scope,那么設(shè)置成最上一行scope的“依賴的依賴”的scope將發(fā)生的變化列表。
?
|
Compile
|
provided
|
runtime
|
test
|
compile
|
compile(*)
|
-
|
runtime
|
-
|
provided
|
Provided
|
provided
|
provided
|
-
|
runtime
|
Runtime
|
-
|
runtime
|
_
|
Test
|
Test
|
-
|
test
|
-
|
?
?
Dependency Management
在parent pom里
使用
< dependencyManagement>
來簡化
dependency
設(shè)置
。舉個(gè)例子:
Project A:
<project>
?...
?<dependencies>
??? <dependency>
????? <groupId>group-a</groupId>
????? <artifactId>artifact-a</artifactId>
????? <version>1.0</version>
????? <exclusions>
??????? <exclusion>
????????? <groupId>group-c</groupId>
????????? <artifactId>excluded-artifact</artifactId>
??????? </exclusion>
????? </exclusions>
??? </dependency>
??? <dependency>
????? <groupId>group-a</groupId>
????? <artifactId>artifact-b</artifactId>
????? <version>1.0</version>
????? <type>bar</type>
????? <scope>runtime</scope>
??? </dependency>
?</dependencies>
</project>
?
Project B:
<project>
?...
?<dependencies>
??? <dependency>
????? <groupId>group-c</groupId>
????? <artifactId>artifact-b</artifactId>
????? <version>1.0</version>
????? <type>war</type>
????? <scope>runtime</scope>
??? </dependency>
??? <dependency>
????? <groupId>group-a</groupId>
????? <artifactId>artifact-b</artifactId>
????? <version>1.0</version>
????? <type>bar</type>
????? <scope>runtime</scope>
??? </dependency>
?</dependencies>
</project>
?
下面通過在parent pom里使用< dependencyManagement>來管理child pom要使用的dependencies。
Parent Project:
<project>
?...
?<dependencyManagement>
??? <dependencies>
????? <dependency>
??????? <groupId>group-a</groupId>
??????? <artifactId>artifact-a</artifactId>
??????? <version>1.0</version>
?
??????? <exclusions>
????????? <exclusion>
??????????? <groupId>group-c</groupId>
??????????? <artifactId>excluded-artifact</artifactId>
????????? </exclusion>
??????? </exclusions>
?
????? </dependency>
?
????? <dependency>
??????? <groupId>group-c</groupId>
??????? <artifactId>artifact-b</artifactId>
??????? <version>1.0</version>
??????? <type>war</type>
??????? <scope>runtime</scope>
????? </dependency>
?
????? <dependency>
??????? <groupId>group-a</groupId>
??????? <artifactId>artifact-b</artifactId>
??????? <version>1.0</version>
??????? <type>bar</type>
??????? <scope>runtime</scope>
????? </dependency>
??? </dependencies>
?</dependencyManagement>
</project>
?
使用上面parent pom就會簡化child pom的dependency設(shè)置:
<project>
?...
?<dependencies>
??? <dependency>
????? <groupId>group-a</groupId>
????? <artifactId>artifact-a</artifactId>
??? </dependency>
?
??? <dependency>
????? <groupId>group-a</groupId>
????? <artifactId>artifact-b</artifactId>
????? <!-- This is not a jar dependency, so we must specify type. -->
????? <type>bar</type>
??? </dependency>
?</dependencies>
</project>
?
注意
:
在上面的
dependency
引用中,非
jar
的必須使用
<type> element
。
Dependency management
的另一個(gè)很有用的用處就是控制
dependency
的版本
。還是舉例:
Project A:
<project>
?<modelVersion>4.0.0</modelVersion>
?<groupId>maven</groupId>
?<artifactId>A</artifactId>
?<packaging>pom</packaging>
?<name>A</name>
?<version>1.0</version>
?<dependencyManagement>
?? <dependencies>
???? <dependency>
?????? <groupId>test</groupId>
?????? <artifactId>a</artifactId>
?????? <version>1.2</version>
???? </dependency>
???? <dependency>
?????? <groupId>test</groupId>
?????? <artifactId>b</artifactId>
?????? <version>1.0</version>
?????? <scope>compile</scope>
???? </dependency>
???? <dependency>
?????? <groupId>test</groupId>
?????? <artifactId>c</artifactId>
?????? <version>1.2</version>
?????? <scope>compile</scope>
???? </dependency>
???? <dependency>
?????? <groupId>test</groupId>
?????? <artifactId>d</artifactId>
?????? <version>1.2</version>
???? </dependency>
?? </dependencies>
?</dependencyManagement>
</project>
?
Project B:
<project>
?<parent>
??? <artifactId>A</artifactId>
??? <groupId>maven</groupId>
??? <version>1.0</version>
?</parent>
?<modelVersion>4.0.0</modelVersion>
?<groupId>maven</groupId>
?<artifactId>B</artifactId>
?<packaging>pom</packaging>
?<name>B</name>
?<version>1.0</version>
?<dependencyManagement>
??? <dependencies>
????? <dependency>
??????? <groupId>test</groupId>
??????? <artifactId>d</artifactId>
??????? <version>1.0</version>
????? </dependency>
??? </dependencies>
?</dependencyManagement>
?<dependencies>
??? <dependency>
????? <groupId>maven-test</groupId>
????? <artifactId>a</artifactId>
????? <version>1.0</version>
????? <scope>runtime</scope>
??? </dependency>
??? <dependency>
????? <groupId>maven-test</groupId>
????? <artifactId>c</artifactId>
????? <scope>runtime</scope>
??? </dependency>
?</dependencies>
</project>
?
上面可以看出project A是project B的parent,A和B都定義a, c, d dependencies,那么如果對project B執(zhí)行maven命令,會采用哪個(gè)定義的呢?答案如下:
-
dependency a and c
將會采用
1.0
版本。
盡管在
parent project A
里定義的
a and d
的版本是
1.2
,但根據(jù)
dependency mediation "nearest definition"
特性,采用的是
project B
定義的版本。
-
dependency b
只在
parent project A
里有定義,因此就采用
project A
的定義。
即使
Dependency c
會使用不同版本的
b,
如果執(zhí)行
project B
還是會采用
project A
定義的版本
(還是根據(jù)
dependency mediation "nearest definition"
特性)。
-
dependency d
的情況和
dependency b
的差不多:由于它在
A
和
B
都用定義,因此是采用
project B
定義的版本
1.0
。假如
Dependency c
會使用不同版本的
d,
如果執(zhí)行
project B
還是會采用
project B
定義的版本(還是根據(jù)
dependency mediation "nearest definition"
特性)。
System scope Dependency
System scope
的
dependencies
總是
available
的,而且不需要從
repository
里獲取,因?yàn)槎x成
system scope
的
dependencies
都是由
JDK or VM
提供的。典型的例子就是
JDBC standard extensions
和
Java Authentication and Authorization Service (JAAS).
例子
:
<project>
?...
?<dependencies>
??? <dependency>
????? <groupId>javax.sql</groupId>
????? <artifactId>jdbc-stdext</artifactId>
????? <version>2.0</version>
????? <scope>system</scope>
????? <systemPath>${java.home}/lib/rt.jar</systemPath>
??? </dependency>
?</dependencies>
?...
</project>
如果你的
artifact
來自
JDK's
tools.jar
,那么
system path
應(yīng)該定義為:
<project>
?...
?<dependencies>
??? <dependency>
????? <groupId>sun.jdk</groupId>
????? <artifactId>tools</artifactId>
????? <version>1.5.0</version>
????? <scope>system</scope>
????? <systemPath>${java.home}/../lib/tools.jar</systemPath>
??? </dependency>
?</dependencies>
?...
</project>
?
Maven dependency and repository (part a)