Maven版本沖突的原因分析和解決指南
之前我們講解了Maven的配置,那么這次我們就講講一些更貼近日常維護(hù)的東西,就是maven的版本控制,在一個(gè)工程的正常生命周期內(nèi)。
我們可能會(huì)因?yàn)楣δ茏兏⑿阅芴嵘?、修?fù)漏洞等多種原因,去更換第三方庫(kù)或框架。此時(shí)就容易發(fā)生版本沖突,本期我們就介紹一下相關(guān)知識(shí),以及如何解決版本沖突。
一、版本沖突的原因
內(nèi)部沖突: 當(dāng)一個(gè)項(xiàng)目直接依賴了不同的版本號(hào),可能會(huì)導(dǎo)致沖突。

模塊間沖突: 一個(gè)庫(kù)內(nèi)部不同模塊之間使用了不同的版本號(hào),或互相引用時(shí),也可能導(dǎo)致沖突。


二、查看與分析沖突
1. 依賴樹
① 原生命令
使用dependency:tree命令查看依賴樹:maven提供了一個(gè)命令mvn dependency:tree,可以查看項(xiàng)目的依賴樹,從而幫助我們分析版本沖突的原因。例如:
mvn dependency:tree
運(yùn)行上述命令,maven會(huì)打印出項(xiàng)目的依賴樹,我們可以根據(jù)這個(gè)依賴樹找到?jīng)_突的版本并解決它。

② Maven Helper
原生命令的可視化成都有限,所以對(duì)于開發(fā)者來(lái)說(shuō),最常用的還是在IDEA上安裝maven helper插件了,我們可以在IDEA插件市場(chǎng)里將其安裝上

安裝并啟用成功后,我們打開某pom文件,就能看到該pom下的依賴情況了

2. 沖突分析
① 查看沖突
在安裝完Maven Helper后, 我們其實(shí)可以直接看到有哪些沖突,如下圖,項(xiàng)目上就存在如下的jar包沖突,當(dāng)我們選中poi-oomxl后,右邊則具體顯示了造成該沖突的具體情況

不難看出,項(xiàng)目中用了多個(gè)不同的組件,而這些組件又使用了不同版本的 poi-oomxl,最終導(dǎo)致在項(xiàng)目中引用了三個(gè)不同版本的 poi-oomxl
② maven的版本規(guī)則
不難看出,盡管項(xiàng)目中依賴了三個(gè)不同的版本,但最后我們實(shí)際在項(xiàng)目中存在的卻只會(huì)有一個(gè) poi-oomxl 組件。那么在發(fā)生沖突時(shí),maven 到底會(huì)取用哪個(gè)版本的組件呢?這就涉及到maven的版本規(guī)則
就近原則(最短路徑)
多條路徑時(shí),選擇最短的路徑(依賴的層級(jí)?。缦?,就會(huì)選用第二條路徑,最后選擇的版本為 version 0.0.2
A —> C —> D —> E —> X(version 0.0.1)A —> F —> X(version 0.0.2)
聲明順序
在路徑相同的情況下,Maven會(huì)選擇最先聲明的版本。如下,就會(huì)選用第一條路徑,最后選擇的版本為 version 0.0.1
A —> C —> X(version 0.0.1)A —> F —> X(version 0.0.2)
我們來(lái)看一個(gè)例子,這里maven為我們選擇了4.1.2,就是因?yàn)槲覀冎苯釉趐om文件里指定了版本4.1.2,所以它就只有一層,是最短路徑。

如果我們把pom里的直接引用內(nèi)容注釋掉

那么就會(huì)用新的最短路徑了,最終選取的版本為4.1.1

③ 版本選擇
一般來(lái)說(shuō),我們相信組件都具有“向下兼容”的能力,即低版本組件的功能,在高版本上應(yīng)該也能使用。所以當(dāng)出現(xiàn)組件沖突時(shí),我們往往選擇保留目前的最高版本。
三、maven解決版本沖突的方法
1. 排除依賴
當(dāng)我們發(fā)現(xiàn)某個(gè)依賴引起了沖突,可以使用 maven 的exclude標(biāo)簽排除它。例如:
<dependencies>
<dependency>
<groupId>example.group</groupId>
<artifactId>example.artifact</artifactId>
<version>1.0</version>
<!-- <exclusions> 元素用于排除指定的依賴 -->
<exclusions>
<exclusion>
<groupId>conflict.group</groupId>
<artifactId>conflict.artifact</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
上述代碼中,假如 example.artifact 引用了某個(gè)版本的 conflict.artifact ,與其他地方引用的conflict.artifact 發(fā)生沖突,我們就可以這樣,把example.artifact 里的 conflict.artifact 剔除掉。如果是使用插件的話,則更方便,右鍵選中組件,即可以快速進(jìn)行 exclude

2. 依賴管理
但是使用 exclusions 也有比較麻煩的地方,exclusions 只對(duì)當(dāng)前依賴有效,并不會(huì)影響其他依賴。因此,如果項(xiàng)目中有多個(gè)依賴引入了相同的沖突依賴,需要在每個(gè)依賴中都使用 exclusions 元素進(jìn)行排除。所以,有時(shí)候我們希望明確指定某個(gè)依賴的版本號(hào),可以使用maven的dependencyManagement標(biāo)簽來(lái)達(dá)到目的
① 單模塊
如下 在pom文件中,我們加入dependencyManagement,并在其中指定了poi-ooxml的版本號(hào)為4.1.2(注意dependencyManagement只有管理信息的功能,并沒有真實(shí)引用poi-ooxml,所以后面的引用段落仍然要保留)

然后在引用的段落里,把版本號(hào)清除掉

此時(shí)我們?cè)偃タ匆们闆r,就會(huì)發(fā)現(xiàn)所有的引用全部變成了 4.1.2,不再有沖突提示

② 跨模塊處理
多模塊的管理,更加需要使用 dependencyManagement 來(lái)確保各子模塊在使用相同版本的組件。所以此時(shí)需要在父POM文件中加入dependencyManagement
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>parent-project</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>pom</packaging>
<modules>
<module>../child1</module>
<module>../child2</module>
<module>../child3</module>
</modules>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>4.1.2</version>
</dependency>
</dependencies>
</dependencyManagement>
</project>
然后在所有子模塊的pom文件里只保留引用,不再指定版本號(hào),如下
<dependencies>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
</dependency>
</dependencies>
此時(shí),所有子模塊凡是引用了poi-ooxml的, 就都會(huì)指定使用 4.1.2 版本,而不會(huì)再產(chǎn)生沖突了。當(dāng)然,如果某個(gè)子項(xiàng)目需要指定一個(gè)特殊的版本號(hào)時(shí),只需要在自己項(xiàng)目的pom.xml中顯示聲明一個(gè)版本號(hào)即可,因?yàn)榫徒瓌t的關(guān)系,該模塊會(huì)使用自己指定的版本號(hào)
四、結(jié)論
在軟件開發(fā)過(guò)程中,版本沖突是一個(gè)常見的問(wèn)題。我們本次就了解maven在發(fā)生版本沖突時(shí),該如何查看沖突情況,并知道m(xù)aven選擇哪個(gè)版本是遵循就近原則、與聲明順序的。而在處理時(shí)我們可以使用排包(exclusive)法,或者顯示的使用 dependencyManagement 來(lái)指定版本號(hào)。
以上就是Maven版本沖突的原因分析和解決指南的詳細(xì)內(nèi)容,更多關(guān)于Maven版本沖突解決的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Jenkins服務(wù)器更新密鑰后任務(wù)構(gòu)建不了的排查實(shí)錄與解決方案
在一次生產(chǎn)環(huán)境的 SSH 密鑰輪換中,我遇到了一個(gè)極其令人困惑的問(wèn)題:在 Jenkins 服務(wù)器上手動(dòng)執(zhí)行 ssh -i 命令測(cè)試新密鑰到目標(biāo)服務(wù)器,直接報(bào) Permission denied,本文記錄了完整的排查過(guò)程,希望能幫助遇到類似故障的運(yùn)維人員快速定位問(wèn)題,需要的朋友可以參考下2026-05-05
深入淺出的學(xué)習(xí)Java ThreadLocal
本文會(huì)基于實(shí)際場(chǎng)景介紹ThreadLocal如何使用以及內(nèi)部實(shí)現(xiàn)機(jī)制。 具有很好的參考價(jià)值,下面跟著小編一起來(lái)看下吧2017-02-02
利用synchronized實(shí)現(xiàn)線程同步的案例講解
這篇文章主要介紹了利用synchronized實(shí)現(xiàn)線程同步的案例講解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2021-02-02
Java實(shí)現(xiàn)京東聯(lián)盟API數(shù)據(jù)獲取功能
這篇文章介紹了Java獲取京東聯(lián)盟API數(shù)據(jù)的方法,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-07-07
SSM框架中測(cè)試單元的使用 spring整合Junit過(guò)程詳解
這篇文章主要介紹了SSM框架中測(cè)試單元的使用 spring整合Junit過(guò)程詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-09-09
spring-boot項(xiàng)目啟動(dòng)遲緩異常排查解決記錄
這篇文章主要為大家介紹了spring-boot項(xiàng)目啟動(dòng)遲緩異常排查解決記錄,突然在本地啟動(dòng)不起來(lái)了,表象特征就是在本地IDEA上運(yùn)行時(shí),進(jìn)程卡住也不退出,應(yīng)用啟動(dòng)時(shí)加載相關(guān)組件的日志也不輸出2022-02-02
通過(guò)實(shí)例了解如何在JavaWeb實(shí)現(xiàn)文件下載
這篇文章主要介紹了通過(guò)實(shí)例了解如何在JavaWeb實(shí)現(xiàn)文件下載,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-09-09
Java使用Statement接口執(zhí)行SQL語(yǔ)句操作實(shí)例分析
這篇文章主要介紹了Java使用Statement接口執(zhí)行SQL語(yǔ)句操作,結(jié)合實(shí)例形式詳細(xì)分析了Java使用Statement接口針對(duì)mysql數(shù)據(jù)庫(kù)進(jìn)行連接與執(zhí)行SQL語(yǔ)句增刪改查等相關(guān)操作技巧與注意事項(xiàng),需要的朋友可以參考下2018-07-07

