1. 程式人生 > 程式設計 >使用maven工具解決jar包衝突或重複載入的問題

使用maven工具解決jar包衝突或重複載入的問題

在使用maven開發專案的過程中,經常會遇到jar包重複載入或者jar包衝突的問題的,但是由於有些jar是由於maven的依賴載入自動載入進來的,

而不是開發者自己配置的,特別是當專案中pom中配置的jar包依賴本身很多時,開發者靠自己的經驗,有時很難找出是哪個jar的載入導致載入了

多餘的依賴jar,從而產生衝突。

今天剛好遇到一個借用eclipse中的maven外掛解決jar包依賴衝突的問題,分享一下。

專案中出現的問題如下:

Caused by: java.lang.NoClassDefFoundError: Could not initialize class org.apache.log4j.Log4jLoggerFactory

後經網上搜索加邊上大牛指點發現:

log4j-over-slf4j.jar 和 slf4j-log4j12.jar 在同一個classpath下就會出現這個錯誤。

解決方法:

將slf4j-log4j12.jar從相關的jar中排除

但是檢視maven專案中的pom檔案,自己並沒有配置這個jar的依賴,猜測是maven載入其他jar引入的依賴包。

開啟pom.xml檔案,在Dependency Hierarchy(依賴列表)中檢視jar包的依賴層次關係。

使用maven工具解決jar包衝突或重複載入的問題

在過濾欄中輸入log4j,右側出現了log4j相關包的依賴結構,左側則是pom.xml全部依賴包的列表展示。

直接在右側選中zookeeper底下的slf4j的jar包,右鍵選擇Exclude,然後儲存pom.xml。這樣在載入zookeeper的jar包時就不會再載入slf4j的jar包。

使用maven工具解決jar包衝突或重複載入的問題

修改後對應的dependency檔案如下:

<dependency>
 <groupId>org.apache.zookeeper</groupId>
 <artifactId>zookeeper</artifactId>
 <version>3.4.6</version>
 <exclusions>
 <exclusion>
  <artifactId>slf4j-log4j12</artifactId>
  <groupId>org.slf4j</groupId>
 </exclusion>
 </exclusions>
 </dependency>

這樣就能通過filter過濾快速找到對應jar,並知道他的依賴關係,快速解決專案中的jar包衝突問題。

補充知識:解決Maven重複依賴問題(同一個jar,多個版本)

問題描述

現在開發專案,一般都會建立maven工程,用它來管理依賴實在是方便了,當然它還有其它用途。但是在實際的情況中往往會有重複依賴的問題,比如建立的工程A,依賴了b-1.0.jar,而b-1.0.jar又依賴了d-1.0.jar(這個我們本身是不能直接看到的),同時我們自己的工程又依賴了d-2.1.jar,或者工程A依賴了c-1.0.jar,c-1.0.jar依賴了d-2.0.jar,顯然,d.jar有3個版本,3者之間是重複的,甚至是衝突的。如下圖所示:

使用maven工具解決jar包衝突或重複載入的問題

重複依賴會怎麼樣?

首先從工程角度來講,引用了同一個Jar的不同版本,這肯定是依賴有問題,或者就是錯誤的。

其次,重複依賴,在專案啟動過程當中可能會有一些警告資訊。

當然,最重要的是引發程式碼異常,最常見的就是NoSuchMethod。

解決思路

尋找重複引用的jar。

定位這些Jar在哪裡被引用了。

接下來需要分析舍與留,原則上保留高版本,大多數情況下是向下相容的。但是不一定,有時候也得保留低版本,或者有時候兩者都需要保留。

如果是一個工程,其實處理起來還比較好處理。但是如果有多個工程,最終我們可能將所有的依賴合在一塊兒。處理起來可能會稍微麻煩些,比如工程1依賴了2.1版本,工程2依賴了2.2版本,你把工程1的2.1的依賴去掉,但同時還需要把2.2的加在工程1上面,否則可能編譯不通過。

最重要的就是,調整之後,儘可能做全面測試。特別是一些間接依賴,如果去除的話,編譯不會有問題,但執行起來會有問題。

具體解決過程

上述5個步驟,重點說一下1和2.

尋找重複引用的jar

觀察法:把所有的jar依賴打包到同一個目錄下,觀察。

執行法:執行階段會報錯,一旦報錯,基本上就定位到了。

掃描法:專業的測試人員,可以進行掃描jar包並統計。

搜尋法:依靠maven進行搜尋,這個方法在接下來會講到。

定位Jar被依賴的地方

在maven工程處開啟命令列,輸入:

mvn dependency:tree -Dverbose > tree.txt

這個命令會把這個工程pom.xml裡面所有的依賴通過樹的形狀展示出來,tree.txt:

使用maven工具解決jar包衝突或重複載入的問題

樹形結構其實看得比較清楚,裡面有一些關鍵資訊,比如:

omitted for duplicate

這個意思是依賴是重複的,當然這個沒有關係。

當然還有一些衝突提醒,上圖沒有,如下:

omitted for conflict with 0.5.3

顯示就是這個版本與0.5.3這個版本衝突了,這個也是我上面說到的搜尋法,你可以直接搜尋“conflict”這個單詞,就可以了。當然這種方式僅限單個工程。

拿到這棵樹以後,怎麼辦呢?

前提是我們已經知道了哪個jar包衝突了,那直接就在文本里面搜尋,找到不同版本的引用之處,然後慎重考慮之後,通過exclusions標籤進行去除,如下:

<dependency>
 <groupId>jaxen</groupId>
 <artifactId>jaxen</artifactId>
 <version>1.1.1</version>
 <exclusions>
 <exclusion>
  <groupId>xerces</groupId>
  <artifactId>xercesImpl</artifactId>
 </exclusion>
 </exclusions>
 </dependency>

到此結束。去除的同時需要考慮的一些問題,在解決思路里面提及了一些。希望能給大家一個參考,也希望大家多多支援我們。