maven详解之坐标与依赖
2019獨角獸企業重金招聘Python工程師標準>>>
看著簡單而又復雜的pom.xml文件,看似熟悉,當自己編寫的時候覺得簡單,但是看人家項目的時候又覺得復雜的很,現在我們一起來分析這個pom文件。
Maven的坐標為各種構件引入了秩序,任何一個構件都必須明確的定義自己的坐標,maven的坐標包括如下的元素:
groupId: 定義當前Maven項目隸屬的實際項目
artifactId: 該元素定義實際項目中的一個Maven項目或模塊
version: 該元素定義Maven項目當前所處的版本
packaging: 該元素定義Maven項目的打包方式
classifier: 該元素用來幫助定義構建輸出的一些附屬構件
注:groupId、artifactId、version、packaging是必須定義的,classifier是不能被直接定義的,因為附屬構件不是項目直接默認生成的,而是由附加的插件幫助生成的。
元素詳解:
根元素project下的dependencies元素詳解:
dependencies可以包含一個或者多個dependency元素,以聲明一個或多個項目依賴, 其包含的元素:
groupId、artifactId、version:依賴的基本坐標,對于任何一個依賴來說,基本的坐標是最重要的,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產生影響
| 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 | 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只會分析編譯主代碼和測試代碼需要用到的依賴,一些執行測試和運行時需要的依賴它無法發現。
對于項目中的最佳實踐,需要自己多多的嘗試或者看別人的一些分享,這樣對于開發效率會有很大的幫助,當然在項目開發的過程中不斷的優化和調整這種方法也未嘗不可。
轉載于:https://my.oschina.net/u/2418042/blog/491698
創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎總結
以上是生活随笔為你收集整理的maven详解之坐标与依赖的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 梦到什么预示生女儿
- 下一篇: 做梦梦到太阳爆炸什么意思