解決Maven中的依賴衝突
2023-01-07由 程式設計從Ruandy開始 發表于 林業
樹衝突怎麼解決
Maven依賴衝突確實很難解決。這篇文章的目的是讓讀者更好地理解什麼是版本衝突以及為什麼最好避免它們。我將從一個簡短的故事開始,大多數讀者可能會涉及到這個故事。
故事
首先,想象一下您已經開始著手開發一個有趣的大型專案,該專案使用許多不同的技術庫,這些使您的工程師工作變得更加輕鬆。另外一個好處是,Maven可以管理庫下載以及所選擇的庫版本。因此可以輕鬆更新它們。該專案的開發將繼續進行,直到有一天您遇到了一個庫,該庫大大降低了身份驗證開發的複雜性;然後,您決定將其包含在您的專案中。
但是突然之間,您的程式碼行2223中出現錯誤,該行與您正在處理的行不同。首先想到的是,“多麼奇怪!那行程式碼之前從未失敗過;這一定是我的程式碼中的錯誤;我一定是錯誤地建立/配置了一些東西”。但是,您意識到該程式碼沒有任何問題。更徹底的除錯過程“可能”表明,您不知道的庫類中存在NullPointerException或NoSuchMethodException。立即的反應是將庫依賴關係更新為較新的版本。但這不能解決問題。接下來要做的是檢視庫類本身的程式碼。發現該方法/類根本不存在;即使更新了新增到專案中的新庫。
此外,當您決定訪問本地Maven儲存庫。m2時,事情變得更加奇怪 ,並且發現同一庫有兩個不同的版本。您的專案使用的是舊版本,您不知道為什麼…
恭喜你!您剛剛發現了導致專案崩潰的庫的版本衝突。
注意
:在故事中添加了身份驗證庫時,就可以做到這一點。
為什麼會發生?
由於依賴關係可以連結到具有不同版本的其他依賴關係,因此會產生衝突。基於此,我們可以為專案
X
繪製一個依賴關係樹方案 來解釋這一點:
從上面的樹形方案中可以明顯看出, 即使我們沒有在POM中明確指定它們,我們的專案
X
也會使用所有庫(Y,Z和G)。
實際上,在這種情況下, 即使您不知道該庫存在,庫
Z
也會作為Maven依賴庫匯入到您的專案中。這種依賴關係稱為 傳遞依賴關係。
由於
Y
和
G
依賴於
Z的
不同版本 ,因此我們建立了庫衝突版本。該專案 在執行時只能使用一個版本的
Z
庫(1。0或2。0);但不是兩者兼而有之。如果我們使用的庫版本與另一個庫不相容;該專案最終可能會產生錯誤並崩潰。讓我們假設庫
Z
是我們專案中錯誤的根源。並且我們想知道哪個版本的
Z
會導致錯誤。
我們正在使用哪個Z版本?
我們的專案
X
使用稱為依賴關係機制的Maven預設機制 來解決依賴關係,並知道要使用哪個庫。
讓我們看看依賴機制是如何工作的。
首先,將使用庫的版本,其節點最接近依賴關係樹中的根(專案
X
)。但是,如果同一庫有多個版本-節點在樹中處於同一級別,會發生什麼情況?在這種情況下,將使用找到的第一個庫版本。這意味著庫版本的選擇取決於POM檔案中的依賴關係順序,其中首先宣告的那些依賴關係將首先被選擇。
如何解決衝突
解決上述衝突的方法有兩種。第一個也是最簡單的解決方案是 在
X
的POM檔案中將庫
G
匯入到 庫
Y
之前 ;正如我上面解釋的。但是,更巧妙的解決方案是將
Z
的最新版本
(2.0)
匯入 為
X
的直接依賴項 。在
X
的POM檔案中。幸運的是,如果庫
Z
支援向後相容(因為庫
Y
使用
Z的v1.0
),則後一種解決方案將起作用 。在這種情況下,需要進行測試以提高可靠性
重要說明:
如果存在版本衝突,並不總是意味著您的專案將崩潰,當您使用很多庫時通常會發生版本衝突,但是我們必須注意使用的庫版本不會使我們的崩潰專案。
如何更快地發現衝突?
上面的故事中提到的問題是微不足道的,我們很幸運能夠儘快解決。但是,有時候,找到依賴衝突不是一件容易的事。即使您已經知道該錯誤不是由您的程式碼邏輯引起的。
擁有一個測試專案中哪些庫衝突的工具不是很好嗎?你真幸運! Enforcer – Maven的愛鐵拳–就是這樣做的。Enforcer可以透過分析POM檔案中宣告的所有庫來幫助開發人員解決Maven中的依賴衝突。
該外掛使用了許多不同的規則,但我們只對以下一個感興趣:
· dependencyConvergence –確保所有依賴項都收斂到同一版本。
讓我們透過在pom。xml中編寫外掛來配置該外掛以使用該規則:
透過以上配置,您可以 透過專案的命令列(
mvnforcer:enforce
)執行目標
forcer:enforce
;或將目標繫結到Maven階段。這對於查詢可能導致專案崩潰的任何依賴關係衝突非常有用。一旦執行,該外掛將返回一個列表樹,顯示專案內部的所有衝突(如果有):
Dependency convergence error for log4j:log4j:1。2。17 paths to dependency are:
+-com。ricston。conflict:conflict-info:2。1。3-SNAPSHOT
+-org。slf4j:slf4j-log4j12:1。7。6
+-log4j:log4j:1。2。17
and
+-log4j:log4j:1。2。16
如上所示,Enforcer編寫了一個依賴關係樹,其中的根是我們的專案“ conflict-info”。
在這種情況下,庫log4j存在版本衝突。我們有兩個log4j庫版本(1。2。17和1。2。16)。
log4j的版本1。2。16取決於專案“ conflict-info”;而log4j的1。2。17版本則取決於“ slf4j-log4j12”。在編譯和執行時,將使用log4j 1。2。16版,因為它的節點最接近我們專案依賴樹中的根。由於在執行時只能使用一個庫版本,因此“ slf4j-log4j12”將使用相同的版本。
請注意,並非所有的依賴版本衝突都會使您的專案崩潰。Maven的 依賴關係機制 負責選擇庫版本,如前幾節所述。
最後,有更好的機會避免依賴版本衝突;提取依賴項(和首選版本)作為專案的直接子項。這樣可以確保所選版本在該庫的所有子依賴項中使用;前提是所選版本不會使專案崩潰。
結論
該結論提供了有關版本衝突以及如何在專案中解決它們的更多資訊。
解決衝突的方法還有很多。甚至還有幾百頁的書,也說明了使用不同Maven配置的解決方案。本文僅描述解決這些問題的一種方法。
最後,開發這麼多年我也總結了一套學習Java的資料與面試題,如果你在技術上面想提升自己的話,可以關注我,私信傳送領取資料或者在評論區留下自己的聯絡方式,有時間記得幫我點下轉發讓跟多的人看到哦。