標簽(空格分隔): 學習筆記
坐標
實際就像在幾何中,我們用一對坐標(x, y)來表示坐標系中唯一的點;或者我們可以用(經度,緯度)來表示地球上的某一個位置,在Maven的世界中,有坐標來唯一的表示項目。
他們由groupId
, artifactId
, version
, packaging
, classifier
等信息唯一的標識。
依賴
Maven會根據在POM中妹紙的信息自動下載所需要的依賴構件。
依賴的配置
<project>
<dependencies>
<dependency>
<groupId>...</groupId>
<artifactId>...</artifactId>
<version>...</version>
<type>...</type>
<scope>...</scope>
<optional>...</optional>
<exclusions>
<exclusion>
...
</exclusion>
...
</exclusions>
</dependency>
...
</dependencies>
...
</project>
其中,上述依賴元素的意義:
groupId
,artifactId
,version
:依賴的基本坐標,對於任何一個依賴來說,基本坐標是最重要的,Maven根據坐標才能找到需要的依賴;type
: 依賴的類型,對應於項目坐標蒂尼的packaging,大部分情況下為jar;scope
: 依賴的范圍。optional
: 標記依賴是否可選;exclusions
: 用來排除傳遞性依賴。
依賴范圍
這里的依賴范圍主要針對上面scope
而言。
Maven在編譯項目主代碼的時候需要使用一套classpath,其中,編譯,測試,運行使用不同的classpath。
依賴范圍就是用來控制依賴於這三種classpath(編譯classpath,測試classpath,運行classpath)的關系的。。。
- compile: 編譯依賴范圍。如果沒有指定,則默認使用該依賴范圍。使用此依賴范圍的Maven依賴,對於編譯,運行,測試三種classpath都有效。典型的例子是spring-core.
- test: 測試依賴范圍。典型的例子是JUnit.
- provided: 已提供依賴范圍。對於編譯和測試classpath有效,而對運行classpath無效。典型的例子是servlet-api,編譯和測試項目的時候需要該依賴,但在運行項目的時候,由於容器已經提供,就不需要Maven重復的引入了。
- runtime: 運行時依賴范圍。對於測試和運行都有效。典型的例子是JDBC。在項目編譯的時候只需要JDK提供JDBC接口,只有在運行或測試的時候才需要實現上述接口的具體JDBC驅動。
- system: 系統依賴范圍。編譯和測試時有效,應是無效。但使用system范圍的依賴時必須通過systemPath元素顯示地指定依賴文件的路徑。由於此類依賴不是通過Maven倉庫解析的,而且往往與本機系統綁定,可能造成構建的不可移植,因此應謹慎使用。
- import: 導入依賴范圍。
傳遞性依賴
一個機遇Spring Framework的項目,如果不使用Maven,則在項目中就需要手動下載相關依賴:
做法一:下載一個很大的如spring-framework-2.5.6-with-dependencies.zip
的包,這里包含了所有Spring Frame的jar包,以及依賴的所有其他jar包,但這樣往往會導致引入了很多不必要的依賴;
做法二:只下載spring-framework-2.5.6.zip
的包,到實際應用的時候根據其出錯信息,再依次下載其他的包。
上面兩種做法實際都是很繁瑣的,在Maven中可以使用依賴性傳遞來解決這個問題。Maven會解析各個直接依賴的POM。將那些必要的間接依賴,以傳遞性依賴的形式引入到當前的項目中。
排除傳遞性依賴
例如如下場景:
- 場景一:當前項目中有一個第三方依賴,而這個第三方依賴由於某些原因依賴了另外一個類庫的SNAPSHOT版本(該類庫就成了項目的傳遞依賴),而SNAPSHOT可能是不穩定的,則必然會影響到該項目的穩定性,因此希望能夠將這個傳遞依賴切除。
- 場景二:希望能夠替換某個傳遞性依賴。例如一個項目A依賴一個類庫X,而由於版本的原因,這個類庫並不在中央倉庫中。但是某個公司有個類似的實現包Y。所以我們想做的是將X的依賴切除,然后聲明對Y的依賴。
排除傳遞性依賴實例:
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.park.mvnDemo</groupId>
<artifactId>project-a</artifactId>
<version>1.0.0</version>
<dependencies>
<dependency>
<groupId>com.park.mvn</groupId>
<artifactId>project-b</artifactId>
<version>1.0.0</version>
<exclusions>
<exclusion>
<groupId>com.park.mvnDemo</groupId>
<artifactId>project-c</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.park.mvnDemo</groupId>
<artifactId>project-c</artifactId>
<version>1.0.0</version>
</dependency>
</dependencies>
</project>
需要注意的是:聲明exclusions的時候只需要groupId和artifactId,而不需要version,就可以唯一的定位依賴圖中的某個依賴。(Maven解析后,不可能出現groupId和artifactId相同,但version不同的兩個依賴。)
依賴調解
- 第一原則:路徑最近者優先;
- 第二原則:第一聲明優先。
- 在依賴路徑長度相等的前提下,在POM中依賴聲明的順序決定了誰會被解析使用,順序最靠前的那個依賴優勝。
在理想情況下,是不應該使用可選依賴的。使用的原因是:某一個項目實現了多個特性,而且這些特性間是互斥的。
可選依賴不被傳遞
假設有這樣一個依賴關系:
項目A依賴於項目B,項目B依賴於項目X和Y,而且B對X和Y的依賴都是可選依賴:A->B, B->X(可選), B->Y(可選)。此時,X,Y將不會對A有任何影響,即可選傳遞不會傳遞下去。
可選依賴的配置:
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.juven.mvnDemo</groupId>
<artifactId>project-b</artifactId>
<version>1.0.0</version>
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.10</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>8.4-701.jdbc3</version>
<optional>true</optional>
</dependency>
</dependencies>
</project>
歸類依賴
類似與Java中的常量定義,Maven中的依賴也應該在一個唯一的地方定義版本,並且在dependency聲明中引用這一版本。這樣,在升級一些包的時候只需要修改一處。
實例:
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.park.mvnDemo.account</groupId>
<artifactId>account-email</artifactId>
<name>Account Email</name>
<version>1.0.0</version>
<properties>
<springframework.version>2.5.6</springframework.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${springframework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${springframework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${springframework.version}</version>
</dependency>
</dependencies>
</project>
這里,使用<properties> <springframework.version>2.5.6</springframework.version> </properties>
定義一個Maven屬性,然后后面使用${springframework.version}
來使用這個屬性。
優化依賴
Maven會自動解析所有項目的直接依賴和傳遞性依賴,並且根據規則正確判斷每個依賴的范圍,對於一些依賴沖突,也能進行調節,以確保任何一個構件只有唯一的版本在依賴中存在。-- 得到的依賴成為已解析依賴(Resolved Dependency)。
- 查看項目中的已解析依賴:
- 使用命令
mvn dependency:list
; - 查看當前項目中的依賴樹:
- 使用命令
mvn dependency:tree
; - 分析當前項目中的依賴:
- 使用命令
mvn dependency:analyze
.
如上便是Maven中依賴的主要內容。