maven詳解之座標與依賴

看着簡單而又複雜的pom.xml文件,看似熟悉,當本身編寫的時候以爲簡單,可是看人家項目的時候又以爲複雜的很,如今咱們一塊兒來分析這個pom文件。html


Maven的座標爲各類構件引入了秩序,任何一個構件都必須明確的定義本身的座標,maven的座標包括以下的元素:spring

groupId: 定義當前Maven項目隸屬的實際項目api

artifactId: 該元素定義實際項目中的一個Maven項目或模塊maven

version: 該元素定義Maven項目當前所處的版本ide

packaging: 該元素定義Maven項目的打包方式學習

classifier: 該元素用來幫助定義構建輸出的一些附屬構件測試

注:groupId、artifactId、version、packaging是必須定義的,classifier是不能被直接定義的,由於附屬構件不是項目直接默認生成的,而是由附加的插件幫助生成的。優化


元素詳解:spa

根元素project下的dependencies元素詳解:.net

dependencies能夠包含一個或者多個dependency元素,以聲明一個或多個項目依賴, 其包含的元素:

groupIdartifactIdversion:依賴的基本座標,對於任何一個依賴來講,基本的座標是最重要的,Maven是根據座標來找到須要的依賴

type: 依賴的類型

scope: 依賴的範圍

optional: 標記依賴是否可選(參見可選性依賴)

exclusions: 用來排除傳遞性依賴(參見依賴的傳遞性)


依賴範圍詳解:

Maven在編譯項目主代碼的時候須要使用一套classpath

Maven在編譯和執行測試的時候會使用另一套classpath

Maven在實際運行項目的時候又會使用一套classpath

依賴範圍就是用來控制依賴與這三種classpath(編譯classpath、測試classpath、運行classpath)的關係

Maven的6種依賴範圍:

compile: 編譯依賴範圍(默認),對於編譯、測試、運行三種classpath都有效

test: 測試依賴範圍, 只對測試classpath有效。典型範例:Junit

provided: 已提供依賴範圍 對於編譯和測試classpath有效,但在運行時無效。典型範例:servlet-api

runtime: 運行時依賴範圍 對於測試和運行classpath有效,但在對編譯主代碼時無效。典型範例:JDBC

system: 系統依賴範圍

import: (maven2.0.9及以上): 導入依賴範圍,它不會對三種實際的classpath產生影響

依賴範圍(Scope) 對於編譯classpath有效 對於測試classpath有效 對於運行時classpath有效 例子
compile Y Y Y spring-core
test
Y
junit
provided Y Y
servlet-api
runtime
Y Y JDBC驅動實現
system Y Y
本地的,Maven倉庫以外的類庫文件


瞭解了依賴的基本元素和依賴範圍以後,咱們會發如今咱們項目中常常會出現一些默認的配置問題,致使編譯和運行失敗的狀況,如今讓咱們來學習如何解決這些問題,首先要了解一下依賴的傳遞性


傳遞性依賴和依賴範圍

簡單的說,通常項目中出現問題多數是由於重複的引用或者引用了較低版本的依賴,或者是他們的依賴範圍發生了變化。

舉個例子來理解傳遞性依賴:

咱們建立了一個Maven Project-----learnDependency,而後咱們引入了spring-core這個依賴,而後咱們打開spring-core的 pom.xml發現,spring-core也有本身的依賴:commons-logging,並且該依賴沒有聲明依賴範圍,那麼默認的就是 compile,因此這時咱們就能夠說:commons-logging也是learnDependency的一個依賴,這時咱們就將這種依賴稱之爲傳遞 性依賴,commons-logging是learnDependency的一個傳遞性依賴。有了傳遞性依賴,咱們就能夠在使用的時候不去考慮咱們引入的 依賴究竟是否須要其它依賴,和是否引入多餘的依賴,Maven 會解析各個直接依賴的pom,將必要的間接依賴引入到項目中。


細說傳遞性依賴

假設:A依賴於B,B依賴於C,那麼咱們就說A對於B是第一直接依賴,B對於C是第二直接依賴,A對於C是傳遞性依賴。

由於依賴是有依賴範圍的,那麼對於這種傳遞性依賴Maven又是如何界定其依賴範圍的呢?

當第二直接依賴的範圍是compile的時候,傳遞性依賴的範圍與第一直接依賴的範圍一致;

當第二直接依賴的範圍是test的時候,依賴不會得以傳遞

當第二直接依賴的範圍是provided的時候,只傳遞第一依賴範圍也爲provided的依賴,且傳遞性依賴的範圍一樣是provided;

當第二直接依賴的範圍是runtime的時候,傳遞性依賴的範圍與第一直接依賴的範圍一致,但compile除外,此時傳遞性依賴範圍爲runtime

  compile test provided runtime
compile compile

runtime
test test

test
provided provided
provided provided
runtime runtime

runtime


左側第一列表示第一直接依賴範圍,最上面一行表示第二直接依賴


optional: 有時候咱們不想讓依賴傳遞,那麼可配置該依賴爲可選依賴,將元素optional設置爲true便可。


在咱們瞭解了Maven強大的依賴機制以後,咱們開始解決問題:

常見問題一:依賴的重複引入

以前說過Maven能夠有效的解決依賴的重複引入問題,可是爲何咱們在項目還會出現這類問題呢?先讓咱們來看一下Maven是如何處理重複引入問題的:


情景一:咱們在項目中分別引入了2個依賴A和B,A又依賴的C,C又依賴了D,B也依賴了D,可是這個時候C依賴的D和B依賴的D的版本是不一樣的:

項目----A---C----D

項目----B---D

也就是說,當前項目引入了2次D依賴,那麼這時,Maven將採用第一原則:路徑最近原則


情景二:咱們在項目中分別引入了2個依賴A和B,而A和B又都引入了C,可是,此時A依賴的C和B依賴的C版本是不一致的,那麼這個時候Maven如何處理呢?

這時,第一原則已經不起做用了,

在Maven2.0.8及以前的版本中  和 Maven2.0.9以後的版本Maven對於這種狀況的處理方式是不一致的

確切的說:

在Maven2.0.8及以前的版本中Maven究竟會解析哪一個版本的依賴,這是不肯定的

Maven2.0.9以後的版本中,制定了第二原則:第一聲明者優先

就是說,它取決於在POM中依賴聲明的順序


這個問題就說明了,爲何咱們經常遇到的能夠正常運行的項目,而後咱們增長了一個看似無關的依賴,而後項目就出現了錯誤,就是這個傳遞性依賴搞的鬼!


還要補充說明的一種狀況是可選依賴

爲何會有可選依賴呢?是由於某一個項目實現了多個特性,可是咱們在面向對象的設計中,有一個原則叫:單一職責性原則,就是強調在一個類只有一項職責,而不是糅合了太多的功能,因此通常這種可選依賴不多會出現。


常見問題二:默認引入的依賴----第二直接依賴的版本太低或者依賴了不穩定的快照

這個問題咱們在開發中也常常遇到,在某個第二直接依賴中引入了1.0版本,可是咱們如今想使用2.0版本,這時咱們要如何解決?

引入一個名詞:排除依賴,也能夠叫替換依賴

想實現依賴排除,而後替換成本身想要的依賴,這時咱們要用到的一個配置是<exclusions> 和<exclusion>,咱們可使用這一元素聲明排除依賴,而後顯示的聲明咱們想要的依賴,在<exclusions>中可 以聲明一個或多個<exclusion>來排除一個或多個傳遞性依賴。

注:聲明<exclusion>的時候只須要聲明groupId和artifactId就能惟必定位依賴圖中的某個依賴。

A ------->  B ------×----C(version1.0)

|

C(version2.0)


常見問題三:解決重複的配置

咱們在開發中也常常遇到這樣的狀況,好比在使用spring framework的時候,他們都是來自於同一個項目的不一樣模塊,所以這些依賴的版本都是相同的,並且在未來升級的時候,這些版本也會一塊兒被升級,這時 Maven又提供了一種解決方案------使用properties元素定義Maven屬性,而後引用。

示例:

<properties>  
    <springframework.version>2.5.6</springframework.version>  
</properties>


這個時候咱們就能夠在聲明依賴的時候使用${springframework.version}來替換具體的版本號

<dependency>  
    <groupId>org.springframework</groupId>  
    <artifactId>spring-context-support</artifactId>  
    <version>${springframework.version}</version>  
</dependency>

如何正確的優化依賴

首先咱們必需要對maven的依賴處理方式瞭然於胸,而後咱們就能夠去除多餘的依賴,顯示的聲明必要的依賴,保證每一個構件都只有惟一的版本在依賴中存在

使用命令來查看當前項目的已解析依賴:

mvn dependency : list

通過Maven解析以後,就會構成一個依賴樹

也可使用命令查看當前項目的依賴樹:

mvn dependency : tree

使用命令分析當前當前項目的依賴:

mvn dependency : analyze

該命令執行結果的兩個重要部分:

Used undeclared dependencies: 表示項目中使用到的,可是沒有顯示聲明的依賴

Unused declared dependencies: 表示項目中未使用的,但顯示聲明的依賴

注:dependency : analyze只會分析編譯主代碼和測試代碼須要用到的依賴,一些執行測試和運行時須要的依賴它沒法發現。


對於項目中的最佳實踐,須要本身多多的嘗試或者看別人的一些分享,這樣對於開發效率會有很大的幫助,固然在項目開發的過程當中不斷的優化和調整這種方法也何嘗不可。

相關文章
相關標籤/搜索