我們看一個最常見到的例子:
<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有一個junit dependency。你可能會問:這個dependency從哪里來?junit jar在哪里?
?
A dependency
是對
repository
里的某個
artifact
的引用。
POM
定義了一個
dependency
,執行的時候就會根據
dependency
的
groupId, artifactId and version
,來
search it from repository
。
你根本不需要在
pom.xml
里指明該
dependancy
來自哪個
repository
,
maven
會先查找
local repository
,如果
local repository
存在該
dependancy
引用的
artifact
,就使用它,如果不存在,則搜索所有你設置的
remote repository
,如果找到它,就把它
download
到
local repository
。
缺省狀態下,通常都是從central maven repository(
http://www.ibiblio.org/maven2
)來download artifact。
如果你的
pom.xml
定義了多個
remote repository
,那么就按順序依次試圖從
remote repository
下載
.
?
例如上面的例子,maven會先check local repository看是否有想要的junit artifact,如果沒有,則從remote repository download到local repository。這時,local repository里artifact目錄結構包含:
?
?
下圖是在repository里所有artifact通用的目錄結構:
?
?
groupId是fully qualified domain name,例如為x.y.z,則結構為:
?
?
maven
是如何根據定義的
dependancy
來從
repository
里查找呢?例如上例,就會根據
groupId?“junit”, artifactId “junit”, and version
“
3.8.1”
,在
repository
里查找
~/.m2/repository/junit/junit/3.8.1/junit-3.8.1.jar
。
?
?
dependancy
功能是
maven
最強大的功能和最顯著的優勢。以前
maven
沒出現之前,通常的
project
都會把要用到的
jar files
都放在
project subdirectory
下,或開發一個
web app
,你要把
10
多個
jar
添加到
classpath
,并把它們放到
lib
目錄下。這樣如果你開發
100
個類似的
web app
,你的每一個
web app
開發目錄下面都會包含有這些
jar files
。這樣如果某個
jar
的版本出現更新,就會要更新
100
個
project
里的
jar
。而使用
maven
,就會大大減輕你的工作量。
?
例如,你有100個web app都使用了spring 1.2.6 framework,如果你使用maven,你不需要存儲所有的spring jars到各個project里,你只需要在POM.XML里定義一個spring dependancy,那么如果升級到spring 2.0,只需要把pom.xml里dependancy的<version>修改為2.0即可。
Dependency機制介紹
?
Dependency
機制的三個知識點
-
Transitive Dependencies
-
Dependency Scope
-
Dependency Management
Transitive Dependencies
(可傳遞的依賴)
這是maven 2.0的新特征。
它使你不需要指定
dependency
的位置而自動定位。而且可傳遞的依賴就是說依賴能夠自動繼承和傳遞,例如
project A
依賴
project B
的
artifact
,而
project B
則依賴
project C
的
artifact
,那么在
build project A
時,就會使用到所有
project
、子
project
的依賴。
?
一個project的
依賴的總個數沒有限制,但是如果出現死循環依賴則會出現問題。
?
由于依賴可以傳遞,因此有可能一個project要依賴的東東會很多,因此可以通過下列幾種方式來限制要包括的dependency:
-
Dependency mediation
–
意思是
強烈建議顯式設置你使用的
dependency
的版本號,因為
dependency
可能會有多種版本。目前
Maven 2.0
支持
"nearest definition"
(見下面的解釋)。
注意:如果在
dependency tree
的同一個
depth
里定義了同一個
dependency
的
2
個版本,那么使用先定義的那個版本
。
-
"nearest definition"
表示在
dependencies tree
里最靠近你的
project
的版本。例如,如果
project A
的依賴性為:
A -> B -> C -> D 2.0
和
A -> E -> D 1.0,
那么
D
的
1.0
版本將會被使用。因為從
A
通過
E
到達
D
的路徑是最短的。如果本例你硬是想要使用
D 2.0
,那么你可以在
A
里定義一個
D
的
dependency
。
?
-
Dependency management
–
表示
maven
允許你在你的
pom.xml
里設置你要使用的
depedency
的版本號,即使這個
depedency
你可能不知道是從哪里來的可傳遞依賴,也不知道該依賴定義的版本是什么,你都可以根據“
nearest definition
”法則來在你的
pom.xml
里設置版本號。
例如上面的例子,你可以直接在
A
里設置對
D
的依賴(設置版本號),即使
A
并不直接使用
D
。
?
-
Dependency scope
–
盡量為要包含的
dependencies
設置要用到它的
scope
。
下面會詳細解釋
?
?
Dependency Scope
Dependency scope
是設置什么
stage
要使用它,用來限制依賴的傳遞。
?
總共有5種Scopes:
-
compile
–
這是缺省
scope
,表明是所有任務所需的資源。“
Compile
”
dependencies are available in all classpaths.
-
provided
–
表示該
dependency
是
JDK
部分或應用服務器的
classpath
里已經自帶的資源,
例如
EJB
的
dependency jars
,只需要在
compile
時使用,在例如打包時就不應該把它打包進
jar, war or ear
里,因為
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
依賴
時,
scope
參數的值為
test
來告訴
Maven
這個依賴項只是在測試階段所需的,而不是運行時所需的資源。
-
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.
后面會詳細講解
不同的
scope
會影響“依賴的依賴”的
scope
。下表列出的就是當一個“依賴”的scope設置為最左一列的scope,那么設置成最上一行scope的“依賴的依賴”的scope將發生的變化列表。
?
|
Compile
|
provided
|
runtime
|
test
|
compile
|
compile(*)
|
-
|
runtime
|
-
|
provided
|
Provided
|
provided
|
provided
|
-
|
runtime
|
Runtime
|
-
|
runtime
|
_
|
Test
|
Test
|
-
|
test
|
-
|
?
?
Dependency Management
在parent pom里
使用
< dependencyManagement>
來簡化
dependency
設置
。舉個例子:
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設置:
<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
的另一個很有用的用處就是控制
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執行maven命令,會采用哪個定義的呢?答案如下:
-
dependency a and c
將會采用
1.0
版本。
盡管在
parent project A
里定義的
a and d
的版本是
1.2
,但根據
dependency mediation "nearest definition"
特性,采用的是
project B
定義的版本。
-
dependency b
只在
parent project A
里有定義,因此就采用
project A
的定義。
即使
Dependency c
會使用不同版本的
b,
如果執行
project B
還是會采用
project A
定義的版本
(還是根據
dependency mediation "nearest definition"
特性)。
-
dependency d
的情況和
dependency b
的差不多:由于它在
A
和
B
都用定義,因此是采用
project B
定義的版本
1.0
。假如
Dependency c
會使用不同版本的
d,
如果執行
project B
還是會采用
project B
定義的版本(還是根據
dependency mediation "nearest definition"
特性)。
System scope Dependency
System scope
的
dependencies
總是
available
的,而且不需要從
repository
里獲取,因為定義成
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
應該定義為:
<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)