假設,在 JavaMavenService2
模塊中,log4j
的版本是 1.2.7
,在 JavaMavenService1
模塊中,它雖然繼承於 JavaMavenService2
模塊,可是它排除了在 JavaMavenService2
模塊中繼承 1.2.7
的版本,本身引入了1.2.9
的 log4j
版本。html
此時,相對於 WebMavenDemo
而言,log4j.1.2.7.jar
的依賴路徑是 JavaMavenService1 >> JavaMavenService2 >> log4j.1.2.7.jar
,長度是 3;而 log4j.1.2.9.jar
的依賴路徑是 JavaMavenService1 >> log4j.1.2.7.jar
長度是 2。前端
因此 WebMavenDemo
繼承的是 JavaMavenService1
模塊中的 log 版本,而不是 JavaMavenService2
中的,這叫路徑優先原則(誰路徑短用誰)。java
此外,在路徑相同的狀況下,python
這種場景依賴關係發生了變化,WebMavenDemo
項目依賴 Sercive1
和 Service2
,它倆是同一個路徑,那麼誰在 WebMavenDemo
的 pom.xml
中先聲明的依賴就用誰的版本。這叫先定義先使用原則。linux
好比:先聲明 JavaMavenService1 因此 WebMavenDemo 繼承它的 log4j.1.2.9.jar 依賴c++
<!--先聲明 JavaMavenService1 因此 WebMavenDemo 繼承它的 log4j.1.2.9.jar 依賴-->
<dependency>
<groupId>com.nasus</groupId>
<artifactId>JavaMavenService1</artifactId>
<version>1.0.0</version>
</dependency>
<dependency>
<groupId>com.nasus</groupId>
<artifactId>JavaMavenService2</artifactId>
<version>1.0.0</version>
</dependency>
複製代碼
項目的依賴 service1
和依賴 service2
同時引入了依賴 log4j
。這時,若是依賴 log4j
在 service1
和 service2
中的版本不一致就可能致使依賴衝突。以下圖:算法
注意,上面我用的是可能,並非說知足上面的條件就必定會發生依賴衝突。由於 maven 遵循上面提到的兩個原則:編程
依賴衝突一般兩個錯:NoClassDefFoundError
或 NoSuchMethodError
,逐一講解下致使這兩種錯誤的緣由:小程序
以上圖依賴關係爲例,假設 WebDemo
經過排除 service1
中低版本的依賴,從而繼承 service2
中的高版本的依賴。這時,若是 WebDemo
在執行過程當中調用 log4j(1.2.7)
有,可是升級到 log4j(1.2.9)
就缺失的類 log
,就會致使運行期失敗,出現很典型的依賴衝突時的 NoClassDefFoundError
錯誤。微信
仍是以上圖依賴關係爲例,WebDemo
經過排除 service1
中低版本的依賴,從而繼承 service2
中的高版本的依賴。WebDemo
調用了原來 log4j(1.2.7)
中有的方法 log.info()
,但升級到 log4j(1.2.7)
後,log.info()
不存在了,就會拋出 NoSuchMethodError
錯誤.
因此說,當存在依賴衝突時,僅期望 maven 的兩個原則來解決是不成熟的。不論是路徑優先原則仍是先定義先使用原則,都有可能形成以上的依賴衝突。那麼如何解決它呢?
經過上面的分析咱們應該能理解到,解決依賴衝突的核心就是使衝突的依賴版本統一,並且項目不報錯。
咱們能夠經過運行 maven 命令:mvn dependency:tree
查看項目的依賴樹分析依賴,看那些以來有衝突,仍是以上圖舉例:運行命令以後,查看依賴樹的 log4j 依賴就會獲得錯誤提示: (1.2.7 omitted for conflict with 1.2.9)
知道了如何查看衝突以後,就是解決衝突。
一、嘗試升高 service2
的版本使他依賴的 log
版本與 service1
的 log
版本一致,但它可能會致使 service2
不能工做。
二、若是 service2
是個舊項目,找遍了也沒找到與 service1
版本一致的 log
,這時能夠嘗試拉低 service1
的版本使他依賴的 log
版本與 service2
的 log
版本一致,但可能會致使 service1
不能工做。
你可能說了,這又不行,那又不行,怎麼辦呢?別急,往下看,maven 解決依賴衝突主要用兩種方法:
最理想的情況就是直接排除低版本,依賴高版本,通常狀況下高版本會兼容低版本。若是 service2
並無調用 log4j.1.2.9
升級所摒棄的方法或類時, 可使用 <exclusion>
標籤,排除掉 service2
中的 log
。仍是以上圖舉例:
<dependency>
<groupId>com.nasus</groupId>
<artifactId>service2</artifactId>
<version>1.0.0</version>
<!-- 排除低版本 log4j -->
<exclusions>
<exclusion>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
</exclusion>
</exclusions>
</dependency>
複製代碼
看着到這裏,你可能又說了。若是 service2
有用到 log
升級所摒棄的方法或類;而 service1
又必須用新版本的 log
,怎麼辦?
第一,通常狀況下,第三方依賴不會出現這種狀況。若是出現了,那你就到 maven 中央倉庫找下兼容兩個版本的依賴。若是找不到,那隻能換依賴。
第二,若是是本身公司的 jar 出現這種狀況,那就是大家的 jar 管理很是混亂。建議從新開發,兼容舊版本。
idea plugin 中搜索 maven helper
插件安裝完以後,打開 pom 文件,發現左下角有個 Depandency Analyzer
選項,點擊進入選 conflicts 選項,就能夠看到當前有衝突的 jar 包,在右邊 exclude 掉紅色衝突的版本便可。
若是看到這裏,喜歡這篇文章的話,請轉發、點贊。微信搜索「一個優秀的廢人」,歡迎關注。
回覆「1024」送你一套完整的 java、python、c++、go、前端、linux、算法、大數據、人工智能、小程序以及英語教程。
回覆「電子書」送你 50+ 本 java 電子書。