排除相依性版本衝突

本文將說明相依性版本衝突及如何排解相關問題。

Java 的 Azure 用戶端函式庫依賴於熱門的第三方函式庫,例如以下幾款:

許多 Java 應用程式與框架直接或傳遞地使用這些函式庫,導致 版本衝突。 像 MavenGradle 這類依賴管理器會解析所有依賴,使得類別路徑上的每個依賴只有一個版本。 不過,解決後的相依版本並不保證能與你應用程式中所有依賴使用者相容。 欲了解更多資訊,請參閱 Maven 文件中的「相 依機制導論 」及 Gradle 文件中的「理解相依性解決 」。

API 對直接相依的不相容會導致編譯錯誤。 菱形相依性不相容通常會導致運行時錯誤,如 NoClassDefFoundErrorNoSuchMethodError 或其他 LinkageError。 並非所有函式庫都嚴格遵循語 意版本控制,且有時候會在同一大版本內發生破壞性變更。

診斷版本不匹配問題

以下章節說明如何診斷版本不匹配問題的方法。

使用 Azure SDK for Java 建置工具

Azure SDK for Java 建置工具,於 《Get started with Azure SDK and Apache Maven》中首次推出,有助於識別常見問題。 我們建議你將此建置工具加入專案,並透過將 azure:run Maven 目標加入你的常規建置流程來執行。 有了適當的設定,你可以更主動地識別並解決相依衝突,避免它們在執行時成為問題。

查看相依樹

執行 mvn dependency:treegradle dependencies --scan 顯示你應用程式的完整相依樹,並附上版本號。 mvn dependency:tree -Dverbose 提供更多資訊,但可能誤導。 欲了解更多資訊,請參閱 Maven 文件中的 Apache Maven 相依樹 。 對於你懷疑有版本衝突的每個函式庫,記錄其版本號,並判斷哪些元件依賴於它。

開發與生產環境中的相依性解決可能運作方式不同。 Apache SparkApache FlinkDatabricks 和 IDE 外掛都需要額外的設定來設定自訂相依。 他們也可以自備 Azure 客戶端函式庫或常用元件。 如需詳細資訊,請參閱下列文章:

欲了解更多此類環境中衝突解決的資訊,請參閱本文後半段「建立完整 JAR」章節。

配置 Azure Functions

內部依賴 Azure Functions(僅執行 Java 8)的版本優先於使用者提供的版本。 這種依賴性造成版本衝突,尤其是與 Jackson、Netty 和 Reactor 之間。

要解決此問題,請將環境變數設 FUNCTIONS_WORKER_JAVA_LOAD_APP_LIBStrue1。 務必將 Azure 函式工具(v2 或 v3)更新到最新版本。

備註

這個設定只適用於執行 Java 8 的 Azure 函式,執行 Java 11 的函式不需要特殊設定。

設定 Apache Spark

Azure SDK for Java 支援多個版本的 Jackson,但有時會因建置工具及其相依性解決順序而產生問題。 一個很好的例子是 Apache Spark(3.0.0 及以上版本),它依賴 Jackson 2.10。 雖然它與 Java 的 Azure SDK 相容,但開發者常發現使用的是較新版本的 Jackson,導致不相容性。 為了減輕這個問題,你應該固定一個特定版本的 Jackson(與 Spark 相容的版本)。 欲了解更多資訊,請參閱本文中 支援多個 Jackson 版本 的章節。

如果你使用的是較早期版本的 Spark,或你使用的另一個函式庫需要更早期版本的 Jackson,而 Azure SDK for Java 不支援,請繼續閱讀這篇文章,了解可能的緩解措施。

偵測傑克森運行時版本

在 Azure Core 1.21.0 中,我們新增了執行時偵測功能,並對 Jackson 執行時版本進行了更佳的診斷。

如果你看到 LinkageError (或其任何子類別)與 Jackson API 相關,請查看例外訊息中的執行時版本資訊。 例如:com.azure.core.implementation.jackson.JacksonVersionMismatchError: com/fasterxml/jackson/databind/cfg/MapperBuilder Package versions: jackson-annotations=2.9.0, jackson-core=2.9.0, jackson-databind=2.9.0, jackson-dataformat-xml=2.9.0, jackson-datatype-jsr310=2.9.0, azure-core=1.19.0-beta.2

請尋找來自 JacksonVersion 的警告和錯誤日誌。 欲了解更多資訊,請參閱 Azure SDK for Java 中的「設定日誌」。 例如:[main] ERROR com.azure.core.implementation.jackson.JacksonVersion - Version '2.9.0' of package 'jackson-core' is not supported (too old), please upgrade.

備註

檢查所有 Jackson 套件的版本是否相同。

關於 Azure SDK 所使用的套件清單及支援的 Jackson 版本,請參閱 「支援多個 Jackson 版本 」章節。

緩解版本不匹配問題

以下章節說明如何緩解版本不符問題。

使用 Azure SDK BOM

使用最新穩定的 Azure SDK 物料清單 ,不要在 POM 檔案中指定 Azure SDK 和相依版本。 如果適用,請使用 Azure Spring Boot BOM

Azure SDK BOM 中列出的相依性經過嚴格測試,以避免相依性衝突。

避免不必要的依賴

如果可能,則移除相依性。 有時,應用程式會依賴多個提供基本相同功能的函式庫。 這類不必要的依賴會使應用程式暴露於安全漏洞、版本衝突以及支援與維護成本。

更新相依版本

如果切換到最新的 Azure SDK 物料清單沒有幫助,找出造成衝突的函式庫以及使用它們的元件。 (更多資訊請參見本文前述的 「查看相依樹 」章節。)試著更新到新版本,它能防範安全漏洞,且經常帶來新功能、效能提升和錯誤修正。

避免降級 Azure SDK 版本,因為這可能會暴露你的應用程式已知的漏洞和問題。

陰影庫

有時候無法找到可以一起搭配使用的函式庫,這時就需要使用 shade 技術作為最後的手段。

備註

著色有重大缺點:它增加了套件大小和類別路徑上的類別數量,使程式碼導航和除錯變得困難,無法重新定位 JNI 程式碼,破壞反射,且可能違反程式碼授權等問題。 只有在其他選項都用盡後才應該使用。

遮蔽讓你可以在建置時將相依性加入 JAR,然後重新命名套件並更新應用程式碼,使其使用位於遮蔽位置的程式碼。 菱形依賴衝突不再是問題,因為有兩個不同版本的依賴項。 你可以著色具有衝突傳遞依賴或直接應用依賴的函式庫,如下列表所述:

  • 傳遞依賴衝突:例如,第三方函式庫 A 需要 Jackson 2.9,而 Azure SDK 不支援,且無法更新 A。 建立一個新模組,包含 A 並著色(重新定位)Jackson 2.9,以及可選性地將其他相依關係置 A入。
  • 應用程式相依性衝突:您的應用程式直接使用 Jackson 2.9。 在更新程式碼時,你可以將 Jackson 2.9 著色並重新定位到一個新模組,裡面有重新定位的 Jackson 類別。

備註

用重新定位的 Jackson 類別建立胖 JAR 並不會解決這些例子中的版本衝突——它只會強制執行單一的 Jackson 著色版本。

製作一個胖胖的 JAR

像 Databricks 或 Apache Spark 這類環境有自訂相依管理,並提供像 Jackson 這樣的通用函式庫。 為了避免與提供的函式庫衝突,你可能想建一個包含所有相依關係的胖 JAR 檔案。 更多資訊請參閱 Apache Maven Shade Plugin。 在許多情況下,遷移 Jackson 類別 com.fasterxml.jackson 可以緩解這個問題。 有時這類環境也會帶來自己的 Azure SDK 版本,因此你可能需要重新定位 com.azure 命名空間以避開版本衝突。

了解相容的相依性版本

關於azure-core的特定相依及其版本的資訊,請參閱 Maven 中央存放庫中的azure-core。 下表展示了一些一般性的考量:

依賴性 支援的版本
傑克森 2.10.0 及更新的次要版本是相容的。 欲了解更多資訊,請參閱 「支援多個 Jackson 版本 」章節。
SLF4J 1.7.*
netty-tcnative-boringssl-static (Netty 原生 BoringSSL 靜態版本) 2.0.*
Netty公共模組 4.1.*
反應爐核心 3.X.* - 主要與次要版本號必須完全符合你 azure-core 版本所依賴的版本號。 欲了解更多資訊,請參閱Project Reactor關於 棄用政策

支援多個 Jackson 版本

Azure SDK for Java 支援多種 Jackson 版本。 支援最低的版本是 Jackson 2.10.0。 Azure SDK for Java 用戶端函式庫會根據執行時偵測到的版本調整設定與 Jackson 使用情況。 此調整使得與舊版 Spring 框架、Apache Spark 及其他常見環境的相容性更高。 應用程式可以將 Jackson 版本降級到 2.10.0 或更高,且不會破壞 Azure SDK for Java 用戶端函式庫。

備註

使用舊版 Jackson 可能會暴露應用程式已知的漏洞與問題。 欲了解更多資訊,請參閱 Jackson 函式庫已知漏洞清單

在固定 Jackson 的特定版本時,務必對 Azure SDK 所使用的所有模組都這麼做。這些模組如下列表所示:

  • jackson-annotations
  • jackson-core
  • jackson-databind
  • jackson-dataformat-xml
  • jackson-datatype-jsr310

從 Jackson 遷移到 azure-json

Azure 用戶端函式庫的 Java 正在遷移到 azure-json,該程式不依賴任何第三方元件,並提供共享的原語、抽象和 JSON 輔助工具。

像 Apache Spark、Apache Flink 和 Databricks 這類環境可能會帶來尚未依賴 azure-core的舊版本。azure-json 因此,當您在這類環境中使用更新版本的 Azure 函式庫時,可能會遇到類似 java.lang.NoClassDefFoundError: com/azure/json/JsonSerializable 的錯誤。 你可以透過在azure-json上新增明確的依賴關係來降低此錯誤發生的可能性。

後續步驟

現在你已經熟悉相依性版本衝突以及如何排解,請參考 Java 相依管理 ,了解如何最佳防止衝突的方法。