用dependency:tree查看maven引入jar包的傳遞依賴

maven項目的pom.xml文件給項目導入了不一樣的jar包,有時候不一樣的dependency會引入同一個jar包的不一樣版本。spring

當不一樣版本的jar包被依賴後,可能會出現:apache

  1. 衝突。
  2. 有的版本的jar包不會被classloader引入,而有的代碼確實須要那個沒有被引入的jar包,進而出現錯誤。

在pom.xml文件的目錄下使用mvn dependency:tree命令能夠查看jar包的傳遞依賴。api

使用-Dverbose 參數能夠列出更詳細的信息。tomcat

mvn -Dverbose dependency:treebash

從命令運行的輸出內容來看,該命令執行的時候會從新build一次。eclipse

若是節選輸出內容的其中一部分,多是這樣的:jsp

[INFO] +- org.apache.tomcat:tomcat-servlet-api:jar:7.0.70:compile
[INFO] +- org.apache.tomcat:tomcat-jsp-api:jar:7.0.70:compile
[INFO] |  +- org.apache.tomcat:tomcat-el-api:jar:7.0.70:compile
[INFO] |  \- (org.apache.tomcat:tomcat-servlet-api:jar:7.0.70:compile - omitted for duplicate)
[INFO] +- net.sf.jasperreports:jasperreports:jar:5.6.0:compile
[INFO] |  +- (commons-beanutils:commons-beanutils:jar:1.8.0:compile - omitted for conflict with 1.8.3)
[INFO] |  +- commons-collections:commons-collections:jar:3.2.1:compile
[INFO] |  +- commons-digester:commons-digester:jar:2.1:compile
[INFO] |  |  +- (commons-beanutils:commons-beanutils:jar:1.8.3:compile - omitted for duplicate)
[INFO] |  |  \- (commons-logging:commons-logging:jar:1.1.1:compile - omitted for duplicate)

遞歸依賴的關係列的算是比較清楚了,每行都是一個jar包,根據縮進能夠看到依賴的關係。maven

  • 最後寫着compile的就是編譯成功的。
  • 最後寫着omitted for duplicate的就是有jar包被重複依賴了,可是jar包的版本是同樣的。
  • 最後寫着omitted for conflict with xxxx的,說明和別的jar包版本衝突了,而該行的jar包不會被引入。好比上面有一行最後寫着omitted for conflict with 1.8.3,那麼該行的commons-beanutils:jar:1.8.0不會被引入,只有1.8.3版本的會被引入。

解決重複依賴和衝突的方法:ide

1,修改pom文件中兩個dependency元素的位置。若是兩個dependency都引用了一個jar包,可是版本不一樣,classloader只會加載jar包在pom文件中出現的第一個版本,之後出現的其餘版本的jar包會被忽略。工具

不建議使用該方法,由於引用不一樣版本的jar包自己就是很危險的。

2,使用<exclusions>標籤來去掉某個dependency依賴中的某一個jar包或一堆jar包,<exclusion>中的jar包或者依賴的相關jar包都會被忽略,從而在兩個dependency都依賴某個jar包時,能夠保證只使用其中的一個。

能夠這麼寫:

<dependency>
	<groupId>com.alibaba</groupId>
	<artifactId>dubbo</artifactId>
	<version>2.8.3.2</version>
	<exclusions>
		<exclusion>
			<artifactId>guava</artifactId>
			<groupId>com.google.guava</groupId>
		</exclusion>
		<exclusion>
			<artifactId>spring</artifactId>
			<groupId>org.springframework</groupId>
		</exclusion>	
	</exclusions>
</dependency>

 

對於Jar包衝突問題,咱們開發人員常常都會有碰到,當咱們使用一些jar包中的類、方法等,或者有時遇到一些日誌系統的問題(參考另外一篇文章Jar包衝突致使的日誌問題),咱們會遇到ClassNotFoundException,NoSuchFieldException,NoSuchMethodException 之類的運行時異常,從經驗上咱們就會判斷,Jar包衝突了。解決Jar包衝突問題,每一個人都有每一個人的方法,這裏我介紹一下個人方法,供你們參考。

處理方法

當遇到jar包衝突時,咱們首先肯定是哪一個jar包衝突了,這個很容易,看咱們調用的類或方法,是屬於哪一個Jar包。而後就是要找出衝突了,我這裏使用命令

mvn dependency:tree -Dverbose -Dincludes=<groupId>:<artifactId>

填寫上Jar包的groupId和artifactId,能夠只有一個,可是中間的冒號不要少,這樣就會輸出依賴樹,並且是僅包含這個Jar包的依賴樹,這樣那些地方依賴了這個Jar包的那個版本就一目瞭然了。
例如,個人項目中notify-common包存在衝突,咱們使用命令

mvn dependency:tree -Dverbose -Dincludes=:notify-common

獲得依賴樹輸出

[INFO] com.taobao.wlb:bis-server:war:1.0-SNAPSHOT
[INFO] +- com.taobao.wlb:bis-core:jar:1.0-SNAPSHOT:compile
[INFO] |  \- com.taobao.logistics:schedule-client:jar:1.1.1:compile
[INFO] |     \- (com.taobao.notify:notify-common:jar:1.8.15:compile - omitted for conflict with 1.8.19.26)
[INFO] \- com.taobao.notify:notify-tr-client:jar:1.8.19.26:compile
[INFO]    +- com.taobao.notify:notify-common:jar:1.8.19.26:compile
[INFO]    \- com.taobao.notify:notify-remoting:jar:1.8.19.26:compile
[INFO]       \- (com.taobao.notify:notify-common:jar:1.8.19.26:compile - omitted for duplicate)

看一下依賴樹中全部的葉子節點就是全部的notify-common包,咱們能夠看到咱們依賴的bis-core中依賴了schedule-client包,它依賴了一個notify-common包,版本是1.8.15,第四行的後面也提示了這個包同其餘包有衝突- omitted for conflict with 1.8.19.26)。而咱們的系統依賴的notify-tr-client包所依賴的版本是1.8.19.26,因而咱們知道是這裏衝突了,在POM排除掉依賴,OK了。

說明

這裏咱們對咱們執行的命令作一個簡單的說明。

mvn dependency:tree -Dverbose -Dincludes=<groupId>:<artifactId>

第一部分mvn dependency:tree是maven依賴的分析命令,做用是對咱們的項目的依賴進行分析,並輸出項目依賴樹
第二部分-Dverbose的做用是添加了verbose一個環境變量,起的做用是在分析項目依賴時輸出明細,這樣項目中依賴的全部引用都會被輸出出來,包含了全部的間接引用,會有不少不少,咱們只須要咱們要找的,因此就須要第三個參數了

第三部分-Dincludes=<groupId>:<artifactId>的做用就是進行過濾,只包含咱們想要的依賴的依賴時,排除掉其它不須要的,依賴樹的全部葉子節點就是咱們的找的依賴包。其中的groupId和artifactId能夠只填寫一個,爲了保證準確性,通常都會填兩個(填寫時不包括尖括號)。

其餘方法:

一、對於maven工程,個人辦法是使用eclipse來解決,點開pom.xml,切換到hierarchy dependency,右上角搜索對應的包,能夠清晰地看到衝突版本

二、可使用idea,在pom.xml中右單擊 選擇Diagrams-》show dependencies

三、mvn dependency:tree -Dverbose > tree.log 
直接輸出衝突的jar文件

Maven依賴

1. 依賴的配置

    根元素project下的dependencies能夠包含一個或多個dependency元素,以聲明一個或多個依賴。每一個依賴能夠包含的元素有:
groupId、artifactId和version:依賴的基本座標,座標三元素。
type:依賴的類型,對應於項目定義的packaging,大部分狀況下不須要定義,使用默認值jar。
scope:依賴的範圍。
optional:標記依賴是否可選。
exclusions:用來排除傳遞性依賴。

2. 依賴的範圍

依賴範圍(scope) 對於編譯classpath有效 對於測試classpath有效 對於運行時classpath有效
編譯依賴範圍:compile Y Y Y
測試依賴範圍:test - Y -
已提供依賴範圍:provided Y Y -
運行時依賴範圍:runtime - Y Y
系統依賴範圍:system Y Y -

另外還有導入依賴範圍:import,該範圍不會對三種classpath產生實際的影響。

3. 傳遞性依賴,和數學裏的傳遞性,是一樣的概念。

    當A有一個compile範圍的B依賴,B有一個compile範圍的C依賴,那麼C就會成爲A的compile範圍依賴,C是A的一個傳遞性依賴。
    有了傳遞性依賴的機制,在使用某個依賴時就不須要考慮它依賴了什麼,也不須要擔憂引入多餘的依賴。Maven會解析各個直接依賴的POM,將那些必要的間接依賴,以傳遞性依賴的形式引入到當前的項目中。
    須要注意的是,可選依賴不會被傳遞。

4. 依賴範圍影響傳遞性依賴

  compile test provided runtime
compile compile - - runtime
test test - - test
provided provided - provided provided
runtime runtime - - runtime

5. 依賴調解

 當兩個依賴路徑上有兩個版本的依賴X時,有如下兩個依賴調解原則:
第一原則:路徑最近者優先;
第二原則:路徑長度同樣時,第一聲明者優先。

6. 排除依賴

當項目A依賴於項目B,可是不想引入傳遞性依賴C,而是本身顯示的聲明對項目C另外一個版本的依賴,使用exclusions元素聲明排除性依賴。

    exclusions能夠包含一個或者多個exclusion子元素,聲明exclusion時只須要groupId和artifactId,不須要version元素。

7. 歸類依賴

當項目中依賴了同一項目的不一樣模塊,它們的版本都是相同的,所以在升級的時候,這些依賴的版本會一塊兒升級。爲了不重複,且須要修改時只修改一處,能夠經過歸類依賴來解決。

    使用properties元素定義Maven屬性,如springframework.version子元素,並定義其值。有了這個屬性定義,maven運行時會將POM中全部的${springframwork.version}替換成定義的實際值。

8. 優化依賴

使用dependency:list和dependency:tree 幫助咱們詳細瞭解項目中全部依賴的具體信息。

使用dependency:analyze工具能夠幫助分析當前項目的依賴。

analyze的結果中包含了兩部分:

Used undeclared dependencies:項目中使用但未顯式聲明的依賴。這種依賴意味着潛在的風險;

Unused declared dependencise:項目中未使用的,但顯式聲明的依賴。對於這種依賴不能直接刪除,由於analyze只會分析編譯和測試須要的依賴,其餘依賴它沒法發現,所以須要仔細分析。

相關文章
相關標籤/搜索