如何在IDEA中快速解決Jar沖突詳解
一、為什么會(huì)產(chǎn)生Jar包沖突?
作為 Java 開發(fā)人員,我們可能會(huì)使用 Maven
維護(hù)許多應(yīng)用程序以進(jìn)行依賴項(xiàng)管理。這些應(yīng)用程序需要不時(shí)升級(jí)以保持最新狀態(tài)并添加新功能或安全更新。
由于某些依賴項(xiàng)之間的沖突,這個(gè)簡(jiǎn)單的任務(wù) - 更新依賴項(xiàng)的版本,很容易變成一場(chǎng)噩夢(mèng)。解決這些依賴沖突可能需要很多時(shí)間。
1.1 直接與傳遞依賴
Maven
中有兩種類型的依賴項(xiàng):
直接依賴項(xiàng):
部分中明確包含在我們的項(xiàng)目對(duì)象模型 ( pom.xml
) 文件中的依賴項(xiàng)<dependencies>
。可以使用<dependency>
標(biāo)簽添加它們。以下是添加到pom.xml文件中的日志庫(kù)示例:
<dependencies> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency> </dependencies>
傳遞依賴項(xiàng):
我們作為依賴項(xiàng)包含在項(xiàng)目中的項(xiàng)目,如上面的日志庫(kù),可以在pom.xml
文件中聲明自己的依賴項(xiàng)。然后將這些依賴項(xiàng)視為對(duì)我們項(xiàng)目的傳遞性依賴項(xiàng)
。當(dāng) Maven
拉取一個(gè)直接依賴時(shí),它也會(huì)拉取它的傳遞依賴。
1.2 Maven 的傳遞依賴
現(xiàn)在我們對(duì) Maven
中的不同依賴類型有了一個(gè)概述,讓我們?cè)敿?xì)看看 Maven
如何處理項(xiàng)目中的傳遞依賴。
作為示例,我們將查看 Spring 框架中的兩個(gè)依賴項(xiàng):spring-context
和spring-security-web
.
在pom.xml
文件中我們將它們添加為直接依賴項(xiàng),特意選擇了兩個(gè)不同的版本號(hào):
<dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.3.5</version> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-web</artifactId> <version>5.4.5</version> </dependency> </dependencies>
使用依賴樹可視化版本沖突
不了解傳遞依賴的人會(huì)認(rèn)為使用這個(gè)依賴聲明只會(huì)拉取兩個(gè) JAR
文件。幸運(yùn)的是,Maven
提供了一個(gè)命令,它將向我們展示與這兩個(gè)依賴項(xiàng)相關(guān)的確切內(nèi)容。
我們可以使用以下命令列出所有依賴項(xiàng),包括可傳遞的依賴項(xiàng):
mvn dependency:tree -Dverbose=true
我們使用此命令的詳細(xì)模式,以便 Maven
告訴我們選擇一個(gè)版本的依賴項(xiàng)而不是另一個(gè)版本的原因。
結(jié)果是這樣:
+- org.springframework:spring-context:jar:5.3.5:compile
| +- org.springframework:spring-aop:jar:5.3.5:compile
| | +- (org.springframework:spring-beans:jar:5.3.5:compile - omitted for duplicate)
| | \- (org.springframework:spring-core:jar:5.3.5:compile - omitted for duplicate)
| +- org.springframework:spring-beans:jar:5.3.5:compile
| | \- (org.springframework:spring-core:jar:5.3.5:compile - omitted for duplicate)
...
+- (org.springframework:spring-expression:jar:5.2.13.RELEASE:compile - omitted for conflict with 5.3.5)
\- org.springframework:spring-web:jar:5.2.13.RELEASE:compile
+- (org.springframework:spring-beans:jar:5.2.13.RELEASE:compile - omitted for conflict with 5.3.5)
\- (org.springframework:spring-core:jar:5.2.13.RELEASE:compile - omitted for conflict with 5.3.5)
我們從兩個(gè)依賴開始,在這個(gè)輸出中,我們發(fā)現(xiàn) Maven
拉取了額外的依賴。這些額外的依賴只是傳遞性的。
我們可以看到樹中有相同依賴項(xiàng)的不同版本。例如,有兩個(gè)版本的spring-beans
依賴項(xiàng):5.2.13.RELEASE
和5.3.5
.
Maven解決了此版本沖突,但是如何解決?什么是省略了重復(fù)和省略的沖突是什么意思?
1.3 Maven 如何解決版本沖突?
首先要知道的是,Maven 無法對(duì)版本進(jìn)行排序:版本是任意字符串,可能不遵循嚴(yán)格的語義序列。例如,如果我們有兩個(gè)版本1.2和 1.11,我們知道1.11在 之后1.2但字符串比較給出了1.11之前1.2。其他版本值可以是1.1-rc1 或 1.1-FINAL,這就是為什么按 Maven 對(duì)版本進(jìn)行排序不是解決方案的原因。
這意味著 Maven 不知道哪個(gè)版本是新的或舊的,并且不能選擇總是采用最新的版本。
其次,Maven采用樹深度最近的傳遞依賴并且根據(jù)解析順序中排第一位的版本去解決。為了理解這一點(diǎn),讓我們看一個(gè)例子:
我們從一個(gè) POM 文件開始,它有一些具有傳遞依賴關(guān)系的依賴關(guān)系(簡(jiǎn)而言之,所有的依賴關(guān)系都用字母 D 表示):
D1(v1) -> D11(v11) -> D12(v12) -> DT(v1.3)
D2(v2) -> DT(v1.2)
D3(v3) -> D31(v31) -> DT(v1.0)
D4(v4) -> DT(v1.5)
請(qǐng)注意,每個(gè)直接依賴項(xiàng)都會(huì)引入不同版本的DT
依賴項(xiàng)。
Maven
將創(chuàng)建一個(gè)依賴樹,并按照上面提到的標(biāo)準(zhǔn),將選擇一個(gè)依賴項(xiàng)DT
:
我們注意到解析順序在選擇DT
依賴項(xiàng)方面發(fā)揮了重要作用,因?yàn)?code>v1.2和v1.5
具有相同的深度,但v1.2
在解析順序中排在第一位。所以即使v1.2
不是 的最后一個(gè)版本DT
,Maven
也選擇了它來使用。
如果我們想v1.5
在這種情況下使用 version
,我們可以簡(jiǎn)單地在我們的 POM
文件中添加D4
之前的依賴項(xiàng)D2
。在這種情況下,v1.5
將首先按照解析順序,Maven 將選擇它。
因此,為了幫助我們理解上面的依賴樹結(jié)果,Maven
為每個(gè)傳遞依賴指明了為什么它被省略:
- “省略重復(fù)” 意味著
Maven
更喜歡另一個(gè)具有相同名稱和版本的依賴項(xiàng)而不是這個(gè)依賴項(xiàng)(即另一個(gè)依賴項(xiàng)根據(jù)解析順序和深度具有更高的優(yōu)先級(jí)) - “因沖突而省略” 意味著
Maven
更喜歡另一個(gè)具有相同名稱但版本不同的依賴項(xiàng)(即根據(jù)解析順序和深度,具有不同版本的另一個(gè)依賴項(xiàng)具有更高的優(yōu)先級(jí))
現(xiàn)在我們很清楚 Maven
是如何解決傳遞依賴的。出于某種原因,有一天我們可能會(huì)選擇一個(gè)特定版本的依賴項(xiàng),并擺脫 Maven
為選擇它所做的所有過程。為此,我們有兩個(gè)選擇:
1.4 覆蓋傳遞依賴版本
如果我們想自己解決依賴沖突,我們必須告訴 Maven
選擇哪個(gè)版本。有兩種方法可以做到這一點(diǎn)。
1.5 使用直接依賴覆蓋傳遞依賴版本
對(duì)于有子模塊的項(xiàng)目,為了確保所有模塊之間的兼容性和一致性,我們需要一種方法來在所有子模塊之間提供相同版本的依賴項(xiàng)。為此,我們可以使用以下dependencyManagement
部分:它為 Maven
提供了一個(gè)查找表,以幫助確定傳遞依賴項(xiàng)的選定版本并集中依賴項(xiàng)信息。
一個(gè)dependencyManagement 部分包含依賴項(xiàng)元素。每個(gè)依賴項(xiàng)都是 Maven 的查找參考,以確定要為傳遞(和直接)依賴項(xiàng)選擇的版本。在本節(jié)中,依賴項(xiàng)的版本是強(qiáng)制性的。但是,在該dependencyManagement 部分之外,我們現(xiàn)在可以省略依賴項(xiàng)的版本,Maven 將從中提供的依賴項(xiàng)列表中選擇正確版本的傳遞依賴項(xiàng)dependencyManagement。
需要注意的是,在dependencyManagementsection 中定義一個(gè)依賴并不會(huì)將其添加到項(xiàng)目的依賴樹中,它僅用于查找引用。
理解使用的更好方法dependencyManagement是通過一個(gè)例子。讓我們回到之前的 Spring 依賴示例。現(xiàn)在我們要玩spring-beans依賴。當(dāng)我們執(zhí)行命令時(shí)mvn dependency:tree,解析的版本spring-beans是5.3.5.
使用dependencyManagement我們可以覆蓋這個(gè)版本并選擇我們想要的版本。我們所要做的就是將以下內(nèi)容添加到我們的 POM 文件中:
<dependencyManagement> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>5.2.13.RELEASE</version> </dependency> </dependencies> </dependencyManagement>
現(xiàn)在我們希望 Maven
解析version 5.2.13.RELEASE
而不是5.3.5
.
讓我們?cè)賵?zhí)行mvn dependency:tree
一次命令。結(jié)果是:
+- org.springframework:spring-context:jar:5.3.5:compile
| +- org.springframework:spring-aop:jar:5.3.5:compile
| +- org.springframework:spring-beans:jar:5.2.13.RELEASE:compile
| +- org.springframework:spring-core:jar:5.3.5:compile
| | \- org.springframework:spring-jcl:jar:5.3.5:compile
| \- org.springframework:spring-expression:jar:5.3.5:compile
\- org.springframework.security:spring-security-web:jar:5.4.5:compile
+- org.springframework.security:spring-security-core:jar:5.4.5:compile
\- org.springframework:spring-web:jar:5.2.13.RELEASE:compile
在依賴關(guān)系樹,我們找到了5.2.13.RELEASE
版本spring-beans
。這是我們希望 Maven
為每個(gè)spring-beans
傳遞依賴解析的版本。
如果spring-beans
是直接依賴,為了利用該dependencyManagement
部分,我們將不再需要在添加依賴時(shí)設(shè)置版本:
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> </dependency>
這樣,Maven
將使用dependencyManagement
部分中提供的信息解析版本。
二、通過IDEA快捷解決依賴沖突
2.1 查找沖突
打開pom.xml
,點(diǎn)擊右鍵Diagrams->Show Dependencies
2.2 發(fā)現(xiàn)沖突
IDEA如果發(fā)現(xiàn)Jar沖突,會(huì)用紅色線高亮現(xiàn)實(shí)。在這里,我們可以發(fā)現(xiàn)pom.xml中有兩個(gè)版本的json-path
包,分別是2.3.0
和2.3.0
2.3 解決沖突
這時(shí)候我們只需要把其中一個(gè)包右鍵選擇Exclude,它就會(huì)自動(dòng)幫我們把對(duì)應(yīng)的jar排除掉,這里我選擇的是把低版本移除
沖突Jar移除后,新的依賴圖已經(jīng)沒有了紅線
pom.xml
文件自動(dòng)添加了一個(gè)排除項(xiàng)
到此這篇關(guān)于如何在IDEA中快速解決Jar沖突詳解的文章就介紹到這了,更多相關(guān)IDEA解決Jar沖突內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
從零實(shí)現(xiàn)一個(gè)簡(jiǎn)單的Spring Bean容器的代碼案例
Spring是一個(gè)非常流行的Java?Web開發(fā)框架,它提供了強(qiáng)大的依賴注入、面向切面編程、聲明式事務(wù)管理等功能,為開發(fā)者提供了高效、快速地構(gòu)建Web應(yīng)用程序的工具,在這篇文章中,咱們將一步一步地構(gòu)建一個(gè)簡(jiǎn)單的SpringBean容器,需要的朋友可以參考下2023-06-06詳解MyBatis直接執(zhí)行SQL查詢及數(shù)據(jù)批量插入
這篇文章主要介紹了MyBatis直接執(zhí)行SQL查詢及數(shù)據(jù)批量插入的相關(guān)知識(shí),需要的朋友一起學(xué)習(xí)吧2016-01-01Java通過反射機(jī)制將對(duì)象封裝成JSON和JsonArray格式
這篇文章主要介紹了Java通過反射機(jī)制將對(duì)象封裝成JSON和JsonArray格式,JAVA反射機(jī)制是在運(yùn)行狀態(tài)中,對(duì)于任意一個(gè)實(shí)體類,都能夠知道這個(gè)類的所有屬性和方法,需要的朋友可以參考下2023-10-10Spring系列中的beanFactory與ApplicationContext
這篇文章主要介紹了Spring系列中的beanFactory與ApplicationContext,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下2022-09-09