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

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


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

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

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

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

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

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

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

③ 版本選擇
一般來說,我們相信組件都具有“向下兼容”的能力,即低版本組件的功能,在高版本上應(yīng)該也能使用。所以當(dāng)出現(xiàn)組件沖突時,我們往往選擇保留目前的最高版本。
三、maven解決版本沖突的方法
1. 排除依賴
當(dāng)我們發(fā)現(xiàn)某個依賴引起了沖突,可以使用 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 引用了某個版本的 conflict.artifact ,與其他地方引用的conflict.artifact 發(fā)生沖突,我們就可以這樣,把example.artifact 里的 conflict.artifact 剔除掉。如果是使用插件的話,則更方便,右鍵選中組件,即可以快速進(jìn)行 exclude

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

然后在引用的段落里,把版本號清除掉

此時我們再去看引用情況,就會發(fā)現(xiàn)所有的引用全部變成了 4.1.2,不再有沖突提示

② 跨模塊處理
多模塊的管理,更加需要使用 dependencyManagement 來確保各子模塊在使用相同版本的組件。所以此時需要在父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文件里只保留引用,不再指定版本號,如下
<dependencies>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
</dependency>
</dependencies>
此時,所有子模塊凡是引用了poi-ooxml的, 就都會指定使用 4.1.2 版本,而不會再產(chǎn)生沖突了。當(dāng)然,如果某個子項目需要指定一個特殊的版本號時,只需要在自己項目的pom.xml中顯示聲明一個版本號即可,因為就近原則的關(guān)系,該模塊會使用自己指定的版本號
四、結(jié)論
在軟件開發(fā)過程中,版本沖突是一個常見的問題。我們本次就了解maven在發(fā)生版本沖突時,該如何查看沖突情況,并知道m(xù)aven選擇哪個版本是遵循就近原則、與聲明順序的。而在處理時我們可以使用排包(exclusive)法,或者顯示的使用 dependencyManagement 來指定版本號。
以上就是Maven版本沖突的原因分析和解決指南的詳細(xì)內(nèi)容,更多關(guān)于Maven版本沖突解決的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Java數(shù)據(jù)結(jié)構(gòu)之實現(xiàn)哈希表的分離鏈接法
今天給大家?guī)淼氖顷P(guān)于Java數(shù)據(jù)結(jié)構(gòu)的相關(guān)知識,文章圍繞著Java哈希表的分離鏈接法展開,文中有非常詳細(xì)的介紹及代碼示例,需要的朋友可以參考下2021-06-06
Java使用備忘錄模式實現(xiàn)過關(guān)類游戲功能詳解
這篇文章主要介紹了Java使用備忘錄模式實現(xiàn)過關(guān)類游戲功能,結(jié)合實例形式詳細(xì)分析了java備忘錄模式的概念、原理及其在過關(guān)類游戲中的具體應(yīng)用方法,需要的朋友可以參考下2018-04-04
SpringBoot配置動態(tài)數(shù)據(jù)源的實戰(zhàn)詳解
Spring對數(shù)據(jù)源的管理類似于策略模式,不懂策略模式也沒關(guān)系,其實就是有一個全局的鍵值對,類型是Map<String, DataSource>,當(dāng)JDBC操作數(shù)據(jù)庫之時,會根據(jù)不同的key值選擇不同的數(shù)據(jù)源,本文介紹了SpringBoot配置動態(tài)數(shù)據(jù)源的方法,需要的朋友可以參考下2024-08-08
SpringBoot如何配置MySQL和Oracl雙數(shù)據(jù)源(Mybatis)
這篇文章主要介紹了SpringBoot如何配置MySQL和Oracl雙數(shù)據(jù)源(Mybatis)問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-03-03
SpringBoot+Netty實現(xiàn)簡單聊天室的示例代碼
這篇文章主要介紹了如何利用SpringBoot Netty實現(xiàn)簡單聊天室,文中的示例代碼講解詳細(xì),對我們學(xué)習(xí)SpringBoot有一定幫助,感興趣的同學(xué)可以了解一下2022-02-02
Java實現(xiàn)數(shù)據(jù)庫連接池的方法
這篇文章主要介紹了Java實現(xiàn)數(shù)據(jù)庫連接池的方法,涉及java數(shù)據(jù)庫連接池的創(chuàng)建、連接、刷新、關(guān)閉及狀態(tài)獲取的常用技巧,具有一定參考借鑒價值,需要的朋友可以參考下2015-07-07
Java基本數(shù)據(jù)類型與封裝類型詳解(int和Integer區(qū)別)
這篇文章主要介紹了Java基本數(shù)據(jù)類型與封裝類型詳解(int和Integer區(qū)別) ,需要的朋友可以參考下2017-02-02

