Maven座標
Maven定義了這樣一組規則,世界上任何一個構件都可以使用Maven座標唯一標識,Maven座標的元素包括groupId、artifactId、version、packaging、classifier(通常不用)。只要我們指定了一組Maven座標,Maven就能在其維護的中央倉庫(http://reop1.maven.org/maven2)中找到相應構件(如果版權允許的話)。
座標含義詳解
例如有如下座標:
<groupId>org.sonatype.nexus</groupId>
<artifactId>nexus-indexer</artifactId>
<version>2.0.0</version>
<packaging>jar</packageing>
這是nexus-indexer的座標定義,它是一個對Maven倉庫編纂索引並提供搜索功能的類庫。下面詳解各標籤含義。
- groupId : 定義當前項目隸屬的實際項目。org.sonatype 是sonatype公司的反向域名,nexus是該公司的研發的一個項目。
- artifactId :定義實際項目中的一個模塊。建議用實際項目名作爲該名稱的前綴,方便查找。如nexus-indexer表示nexus項目中的indexer模塊。
- version:定義當前項目的版本。帶有snapshot標記的表示正在開發中。
- packaging:定義Maven項目打包方式。若不指定,則默認使用jar方式。還可以選擇war來對webapp項目打包。 此例項目最終會生成nexus-indexer-2.0.0.jar文件。
項目依賴
Maven使用依賴的概念來管理項目所引用的包,通過在pom文件中配置依賴,Maven在使用類包會自動根據pom中的配置與中央倉庫下載。
配置依賴
<project>
...
<dependencies>
<dependency>
<groupId>...</groupId>
<artifactId>...</artifactId>
<version>...</version>
<type>...<type>
<scope>...<scope>
<optional>...<optional>
<exclusions>
<exclusion>...<exclusion>
<exclusions>
<dependency>
<dependencies>
...
<project>
<dependencies>
下可以有多個<dependency>
表示項目中的多個依賴。<groupId><artifactId><version>
定義了依賴的基本座標,Maven通過這組座標才能找到相應的依賴。<type>
定義依賴的類型,對應於項目座標下的packaging,默認爲jar<scope>
定義依賴的範圍,默認爲compile。Maven項目在編譯、測試、運行時會使用三套不同的classpath,而不同的依賴範圍會在不同的classpath中起作用。
依賴範圍 | 對於編譯classpath有用 | 對於測試classpath有用 | 對於運行classpath有用 | 例子 |
---|---|---|---|---|
compile | Y | Y | Y | Spring-core |
test | N | Y | N | JUnit |
provided | Y | Y | N | Servlet-api |
runtime | N | Y | Y | JDBC驅動 |
傳遞性依賴
A------> B ------> C
若A依賴B,B依賴C,則A間接依賴於C,即爲傳遞性依賴。例如:
StrutsProject ------> struts2-core ------> common-logging
則在實際項目StrutsProject中只需引入struts2-core依賴,則由於傳遞依賴的特性,Maven會自動下載common-loggging依賴。
依賴調解
若項目通過兩條途徑引入了同一個依賴,如common-logging,但是它們版本不同,即發生了版本衝突問題。Maven提供了兩條原則來解決版本衝突的問題。
- 路徑最近者優先
- 聲明靠前者優先
假設有如下項目依賴,均按聲明順序書寫如下:
A ------> C-2.0 ; A ------> B ------> C-1.0
則依賴C發生了版本衝突,C-2.0的路徑長度爲1,C-1.0的長度爲2,則應該採用C-2.0。
若依賴關係改變如下:
A ------> D ------> C-1.4; A------> B ------- > C-1.0
則兩個版本的C路徑長度都相同,但由於C-1.4先聲明,則應採用C-1.4
排除依賴
若有如下依賴關係
A ------> B ------> C-1.0-snapshot
項目A直接引用依賴B,傳遞性依賴於C,但是項目B所依賴的C還是開發版,並不穩定,若在項目中引入會導致項目的不穩定性,此時需要排除依賴C-1.0-snapshot,並引入C的穩定版本。A的pom.xml文件如下
...
<dependencies>
<dependency>
<groupId>com.maven</groupId>
<artifactId>project-B</artifactId>
<version>1.0</version>
<exclusions>
<exclusion>
<groupId>com.maven</groupId>
<artifactId>project-c</artifactId>
<exclusion>
<exclusions>
<dependency>
<dependency>
<groupId>com.maven<groupId>
<artifactId>project-c<artifactId>
<version>1.1<version>
<dependency>
</dependencies>
...
注意exclusion
元素中排除的依賴,其座標可由groupId和artifactId確定,因爲此項目中該依賴版本唯一。
歸類依賴
通常我們的項目會引入一組相關的依賴,如使用spring框架,則需要引入spring-core-2.5.6,spring-context-2.5.6 spring-beans-2.5.6等等,當spring框架升級時,如果我們手動地更改這些依賴的版本則略顯繁瑣,此處我們引入依賴歸類的方法,將版本定義爲pom.xml的一個屬性,一組依賴引用統一的版本屬性。如下:
<project>
...
<properties>
<spring.version>2.5.6<spring.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
<dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${spring.version}</version>
<dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
<dependency>
<dependencies>
...
</project>
歸類依賴後,維護spring組件的版本只需對spring.version
進行維護了。
優化依賴
- 去除多餘的依賴
- 顯示聲明某些必須的依賴
Maven在解析項目pom文件後,會自動從中央倉庫下載直接依賴和傳遞性依賴,並且調節依賴。這些工作後最後得到的依賴稱爲已解析依賴。可分別用如下兩條命令查看項目的已解析依賴。
mvn dependency:resolved
mvn dependency:list
這些依賴最後會形成一顆依賴樹,通過依賴樹可以很清楚地看見依賴的引入路徑。可使用如下命令查看依賴樹
mvn dependency:tree
典型的依賴樹如下所示:
除了通過這些命令查看項目的依賴關係,還可以使用如下命令來分析項目依賴中的缺陷
mvn dependency:analyze
例如對上圖項目使用該命令如圖
該項目中有兩種項目缺陷:
Used undeclared dependencies
表示該dependency被項目直接使用,(例如import 該包,並直接使用它),但是並沒有被項目直接聲明(在pom文件中用dependency元素顯示聲明),而是由相關依賴傳遞而來。由依賴樹圖可知commons-io是由velocity構件間接引入,但是在程序中直接使用了。這種缺陷雖然在編譯運行時都不會產生錯誤報告,但是會影響項目的穩定性。當對直接依賴velocity升級時,傳遞性依賴commons-io的版本也會相應變動,這種變動有可能導致程序出錯(例如接口的變動),而這種錯誤不易察覺。故在項目中謹記:顯示聲明任何項目中直接使用的依賴Unused declared dependencies
表示項目中顯示聲明的但在編譯階段未使用的依賴。對這類依賴需謹慎處理,可能部分依賴會在測試和運行階段使用。
小結
本文主要介紹了Maven項目的兩個概念,座標與依賴。文中簡要介紹了座標的組成和含義,並詳細介紹了依賴的配置過程以及實踐過程中常用到的處理依賴關係的方法。通過本文,讀者能夠比較透徹地瞭解到Maven的依賴關係,掌握Maven座標的寫法和含義。