2017-06-18 139 views
2

對不起,我的新手問題。java/maven如何在運行時解決依賴衝突

假設我有一個包A,它聲明B,C作爲它的maven文件中的依賴項。 B,C使用兩個不同版本的log4j進行日誌記錄。我有幾個問題:

  1. 如果我使用maven,並聲明B,C作爲A的依賴關係。當maven從mavencentral repo中抽取B,C的神器(.jar)時。做B,C jar文件包含log4j類文件或僅包含它們自己的編譯文件(B,C自己的源代碼,不依賴項)。
  2. 如果我理解正確,當構建發生時,最後,構建中將只有一個log4j類文件(即使B,C使用不同版本的log4j)。在這裏選擇要創建哪個版本的log4j?這是否意味着我需要將log4j聲明爲A依賴項(在A的maven構建文件中) - 並且該版本將被選擇爲構建版本。
  3. B,C可能會使用完全不同的log4j版本。這裏的API可能完全不同。它應該在運行時造成問題?但事實上,這是非常罕見的?爲什麼這樣?

謝謝。

+0

Maven有一個假設,可以始終使用較新版本的工件而不是舊版本。如果不是,則需要在依賴項中使用排除開始播放。 –

回答

1
  1. 它們應該只包含自己的類。不是它們的依賴類。你可以打開jar文件並自己看看。 Jar文件只是zip文件。
  2. Maven將通過選擇與依賴關係樹的根最接近的版本來解決衝突。如果兩個版本在依賴關係樹中處於相同深度,那麼第一個版本會被挑選(IIRC)。如果A本身依賴於log4j,或者如果您希望在運行時使用特定版本,則應該將log4j指定爲A的直接依賴關係,並使用所需的版本。或者至少在構建的dependencyManagement部分指定它。
  3. 由於像Log4J一樣流行的庫努力獲得一個非常穩定的API,因此不會破壞針對較舊版本庫編譯的代碼。
+0

計數器示例:google guava,其中較新版本的舊功能已刪除。 –

+0

番石榴是違反任何形式的版本編號模式存在..他們只是玩他們喜歡的。要麼你買它或不... – khmarbaise

+0

@khmarbaise沒有。他們使用語義版本。 –

0
  1. 一個artefact通常不會包含它的依賴關係(但是有包裝選項)。
  2. Maven將只使用一些規則確定一個版本(我不記得詳細)。如果由於某種原因你必須重寫這個,你可以把一個依賴管理部分放到POM中。
  3. 是的,這可能會導致問題。只有在對公共API進行更改時小心才能避免它們。
3
  1. jar文件通常不包含它們的依賴關係。有一種方法可以做到這一點,稱爲胖罐。 What is a fat JAR?但假設您正在使用常規的jar依賴項。罐子只會在他們自己的pom.xml中聲明他們的依賴關係。所以對於你的例子,B和C將只包含他們自己編譯的源代碼。

  2. 這實際上取決於你如何打包文件。一般來說,如果你只生成一個簡單的jar,它將不包含依賴關係,並且運行者有責任提供正確的依賴關係。例如,在戰爭中,maven會拋出所有的依賴關係。前面提到的另一種方式是胖罐子。另一種常見的方法是壓縮所有依賴項並分別提供它們。

  3. 我不知道爲什麼你之前沒有遇到過沖突,我有很多其他庫,但我不記得log4j的情況。作爲一個圖書館維護人員,處理這類衝突的一種方式是,當你進行非向後兼容的更改時,要更改包名稱,這樣用戶可以在類路徑中安全地擁有多個版本(無論如何都應避免)。

Maven有一種方法可以避免這種衝突,它會優先考慮最接近定義的依賴版本。例如,如果版本a在A中聲明,版本b在B中聲明,那麼有效版本將爲A.

此外,還有一些其他機制,如依賴關係管理。你可以看這裏:https://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html

這個主題是非常嚴重的,可能會導致很多檢測到生產錯誤。希望這有助於...

0
  1. 如果log4j的被指定爲B和C的依賴,你不使用,創造尤伯杯瓶/脂肪罐,B和C將不包含log4j的類特殊的插件文件。

  2. 具有相同座標的一個依賴項(groupId,artifactId)。正如這裏已經提到的某個人,版本通常是通過根到最短路徑來選擇的。所以如果你想使用特定的log4j版本,你可以在你的pom中指定它。

  3. 如果您使用log4j作爲標準方式,即通過指定配置文件,兩個版本(log4j和log4j2)通常可以共存,因爲它們使用不同的軟件包和不同的配置文件。只需檢查log4j的遷移網站:Migration from log4j to log4j2