如何解決包沖突問題


下面舉一個包沖突的例子:

你引用了 2 個三方包 a.jar 和 b.jar , a.jar 中又引用了一個 c.jar ,假設 c.jar 的版本號為 version-1, b.jar 中也引用了 c.jar ,假設這里的 c.jar 相對於 a.jar 中的 c.jar 為較高版本,記為 version-2 , b.jar 中某個類引用了 c.jar 的類 classA 中的方法 method A() ,並且該方法只存在於高版本的 c.jar(version-2) 的類 classA 中,而不存在c.jar(version-1) 的類 classA 中。

當系統編譯加載時,系統可能編譯加載 c.jar(version-1) ,也可能編譯加載 c.jar(version-2) ,當編譯加載c.jar(version-2) 時,由於很多 jar 包都支持向下兼容,即高版本兼容低版本,因此不論 a.jar 調用 c.jar 還是 b.jar 調用 c.jar 一般都不會出問題。但如果此時剛好應用編譯加載的是 c.jar(version-1) 中的類 classA 時,那么 b.jar 調用Method A() 時便會報上述錯誤,因為 Method A() 函數只存在於高版本的 c.jar 中,而此時系統編譯加載的卻是低版本的 c.jar 。

jar包沖突常見的異常為找不到類(java.lang.ClassNotFoundException)、找不到具體方法(java.lang.NoSuchMethodError)、字段錯誤( java.lang.NoSuchFieldError)或者類錯誤(java.lang.LinkageError)

常見的解決方法如下:

1、首先做法是打出工程文件的依賴樹,將根據jar包依賴情況判定是不是同一個jar包依賴了多個版本,如果確認問題所在,直接exclusion其中錯誤的jar包即可;

2、如果通過看依賴樹不能確定具體沖突的jar包,可以使用添加jvm參數的方式啟動程序,將類加載的具體jar信息打印出來;-verbose:class;

3、經過上述步驟基本就可以解決jar包沖突問題,具體的問題要具體分析,當問題不可重現時上述方法均不會奏效。

排包方法:

<dependency>
  <groupId>com.know.diamond</groupId>
  <artifactId>diamond-sdk</artifactId>
  <version>2.0.5</version>
  <exclusions>
      <exclusion>
        <groupId>com.google.collections</groupId>
         <artifactId>google-collections</artifactId>
   </exclusion>
   </exclusions>
</dependency>

當遇到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可以只填寫一個,為了保證准確性,一般都會填兩個(填寫時不包括尖括號)。

其他方法:

1、對於maven工程,我的辦法是使用eclipse來解決,點開pom.xml,切換到hierarchy dependency,右上角搜索對應的包,可以清晰地看到沖突版本

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

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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM