先從項目去看顯而易見,假如我們有一個項目,父工程中包含一些子工程,如下:
我們想看一下samples-account中的依賴關系,那么我們可以打開?samples-account的pom文件,查看其maven依賴關系圖。
我們可以看到此項目中maven的依賴關系如下。
?我們可以看到有很多紅色的虛線和紅色的實線,對于紅色實線來說表示的是maven依賴沖突,對于紅色虛線來說表示的是重復依賴或者是依賴被覆蓋。
因為很亂,我們可以先按如下操作找到哪些有問題的依賴關系。
然后再找到我們要關注的依賴進行分析,如我們要看spring-context-support相關的依賴是否有沖突。我們可以左鍵單擊選中這個節點,然后點擊如下按鈕:
?會自動關注到此依賴,如下圖:
這樣我們可以看到?spring-context-support 有倆版本,且samples-account直接引用過其1.0.5版本,dubbo-config-spring也引用過其1.0.5,dubbo則引用的是他的1.0.11版本(在這里由于就近原則,它的版本被改為1.0.5版本了)。我們從maven樹中也能看到:
?那么jar包后面的omitted for conflict with 1.0.5是什么意思呢?
在 Maven 的依賴樹中,當你看到“omitted for conflict with 1.0.5”這樣的信息時,它意味著 Maven 在解析依賴時遇到了版本沖突,并決定省略(排除)了與指定版本(在此例中為 1.0.5)沖突的那個依賴。
具體來說,Maven 遵循了一套復雜的依賴解析算法,稱為“最近者勝”(nearest wins)策略。當 Maven 檢測到多個庫都依賴了同一個庫的不同版本時,它會根據依賴樹中的層次結構和聲明的順序來決定使用哪個版本。在這個過程中,如果一個依賴被其他依賴以更高的版本或相同的版本引入,那么 Maven 可能會選擇忽略(省略)那個較低版本的依賴。
例如,假設你有以下依賴結構:
- 項目 A 依賴庫 B 1.0.0
- 庫 B 1.0.0 依賴庫 C 1.0.0
- 項目 A 同時直接依賴庫 C 1.0.5
在這種情況下,Maven 會選擇庫 C 的 1.0.5 版本,因為這是一個更直接的依賴,并且版本號更高。同時,它會將庫 B 1.0.0 依賴的庫 C 1.0.0 標記為“omitted for conflict with 1.0.5”,意味著它已經被省略了,以避免版本沖突。
如果你希望明確控制依賴的版本,你可以在項目的?
pom.xml
?文件中使用?<dependencyManagement>
?部分來管理依賴的版本,或者使用?<exclusions>
?標簽來排除不需要的傳遞性依賴。
而omitted for duplicate又是什么意思呢?
?在Maven中,"omitted for duplicate"意味著存在多個具有相同
groupId
和artifactId
的依賴項,但它們的版本不同或傳遞依賴路徑不同,因此Maven或相關的構建工具(如IntelliJ IDEA)認為這些依賴是重復的。具體來說,當Maven解析項目的依賴關系時,如果它發現兩個或多個依賴項指向了同一個庫(即相同的
groupId
和artifactId
),但它們的版本不同,Maven就會嘗試解決這種沖突。Maven的依賴調解機制會選擇一個版本作為“贏家”,并將其他版本標記為“輸家”。被標記為“輸家”的依賴項在依賴樹中可能就會被標記為"omitted for duplicate",表示它們因為與另一個相同但版本不同的依賴項沖突而被省略。這種情況通常發生在項目的依賴關系比較復雜,特別是當項目直接或間接地通過傳遞依賴引入了同一個庫的不同版本時。為了避免這種問題,可以在項目的
pom.xml
文件中使用<dependencyManagement>
部分來管理依賴的版本,或者使用<exclusions>
標簽來排除不需要的傳遞性依賴。
?omitted for conflict with 和 omitted for duplicate有什么區別呢?
在Maven依賴管理的上下文中,
omitted for conflict with
?和?omitted for duplicate
?這兩個術語都與解決依賴沖突有關,但它們在描述沖突的原因和結果時略有不同。
omitted for duplicate:
- 這通常表示在項目的依賴樹中存在多個具有相同
groupId
和artifactId
但可能不同版本的依賴項。Maven的依賴管理策略在處理這些依賴時,會選擇一個版本(通常是最新版本,但也取決于依賴的聲明順序和范圍),而將其他版本視為“重復的”并省略它們。- 當你在Maven的輸出或日志中看到“omitted for duplicate”時,這通常意味著Maven已經自動解決了這個沖突,并選擇了其中一個依賴項版本。
omitted for conflict with:
- 這個術語更具體地指出了哪個依賴項與當前考慮的依賴項存在沖突。它表明,盡管兩個依賴項在
groupId
和artifactId
上匹配,但由于某種原因(例如,它們的版本不兼容或與其他依賴項存在沖突),Maven選擇了省略其中一個。- “conflict with”后面通常會跟著與當前依賴項存在沖突的依賴項的詳細信息,如版本號或
groupId:artifactId
組合。- 與“omitted for duplicate”不同,“omitted for conflict with”可能意味著需要手動干預來解決沖突,特別是當Maven的自動依賴管理策略不能提供一個滿意的解決方案時。
總之,這兩個術語都涉及Maven在構建項目時如何處理依賴沖突,但“omitted for duplicate”更側重于描述多個相同依賴項的存在,而“omitted for conflict with”則更具體地指出了哪個依賴項與當前依賴項存在沖突。
對于這些沖突我們怎么解決呢?
假設你的項目(我們稱之為project-A
)依賴于兩個庫:library-X
和library-Y
。
library-X
?的版本1.0是你的項目直接依賴的。library-Y
?是你的項目直接依賴的另一個庫,但它又間接地依賴于library-X
的版本2.0(作為它的傳遞性依賴)。
在Maven的依賴管理中,這會導致一個沖突,因為你的項目試圖同時使用library-X
的兩個不同版本:1.0(直接依賴)和2.0(通過library-Y
的傳遞性依賴)。
Maven的依賴樹可能看起來像這樣:
project-A
|-- library-X:1.0 (直接依賴)
|-- library-Y:some-version |-- library-X:2.0 (傳遞性依賴)
在這個例子中,Maven會嘗試解決這個沖突。默認情況下,Maven會選擇路徑最短的依賴版本,也就是說,它會盡可能地使用直接聲明的依賴版本。但是,這并不總是可行的,特別是當兩個版本在API或行為上有不兼容的更改的時候。
當然還有項目依賴是這樣沖突的:
1.projectA依賴LibraryB,LibraryB又依賴LibraryX1.0。
2.projectA依賴LibraryC,LibraryC又依賴LibraryX2.0。
ProjectA
|-- LibraryB|-- LibraryX1.0
|-- LibraryC|-- LibraryX2.0
要解決上述Maven依賴沖突問題,你可以通過在項目的pom.xml
文件中配置<exclusions>
標簽來排除不需要的依賴版本。以下是一個示例配置,展示了如何排除LibraryB
中的LibraryX
?1.0版本依賴,以確保ProjectA
只使用LibraryX
的2.0版本(假設這是你想要保留的版本):
<project> ... <dependencies> <!-- ProjectA依賴于LibraryB --> <dependency> <groupId>com.example</groupId> <artifactId>LibraryB</artifactId> <version>1.0</version> <exclusions> <!-- 排除LibraryB中的LibraryX 1.0版本 --> <exclusion> <groupId>com.some.othergroup</groupId> <artifactId>LibraryX</artifactId> </exclusion> </exclusions> </dependency> <!-- ProjectA也依賴于LibraryC --> <dependency> <groupId>com.example</groupId> <artifactId>LibraryC</artifactId> <version>x.y.z</version> <!-- 注意:這里不需要排除LibraryX,因為我們要保留的版本就是LibraryC所依賴的版本 --> </dependency> <!-- 直接指定LibraryX的2.0版本 --> <dependency> <groupId>com.some.othergroup</groupId> <artifactId>LibraryX</artifactId> <version>2.0</version> </dependency> <!-- 其他依賴... --> </dependencies> ...
</project>
看著好像有那么點道理,然而,在上面的配置中,直接指定LibraryX
的2.0版本可能會引發另一個問題:如果LibraryB
確實需要LibraryX
的1.0版本來正常工作,那么這種硬編碼的依賴可能會導致LibraryB
無法正常工作。
因此,更好的做法可能是確保LibraryB
和LibraryC
的維護者都更新他們的依賴項以使用兼容的版本,或者在項目的dependencyManagement
部分統一指定一個兼容的版本(把問題提給項目的維護者吧)。
<project> ... <dependencyManagement> <dependencies> <!-- 統一指定LibraryX的版本為2.0 --> <dependency> <groupId>com.some.othergroup</groupId> <artifactId>LibraryX</artifactId> <version>2.0</version> </dependency> <!-- 其他依賴管理... --> </dependencies> </dependencyManagement> <dependencies> <!-- ProjectA依賴于LibraryB,但不需要顯式排除LibraryX,因為dependencyManagement已經指定了版本 --> <dependency> <groupId>com.example</groupId> <artifactId>LibraryB</artifactId> <version>1.0</version> </dependency> <!-- ProjectA也依賴于LibraryC,同樣不需要顯式排除 --> <dependency> <groupId>com.example</groupId> <artifactId>LibraryC</artifactId> <version>x.y.z</version> </dependency> <!-- 通常情況下,不需要直接指定LibraryX的版本,因為dependencyManagement已經處理了 --> <!-- 其他依賴... --> </dependencies> ...
</project>
?在dependencyManagement
部分指定的版本將作為項目的“首選”版本,Maven將嘗試解析所有依賴以使用這個版本(除非在dependencies
部分明確指定了不同的版本)。
具體依賴可參照這位博主的描述:maven依賴傳遞(直接、間接依賴)、解決依賴沖突(排除依賴、版本鎖定dependencyManagement)_maven 間接依賴-CSDN博客