Freigeben über


Behandeln von Abhängigkeitsversionskonflikten

In diesem Artikel werden Abhängigkeitsversionskonflikte und deren Behandlung beschrieben.

Azure-Clientbibliotheken für Java sind von beliebten Drittanbieterbibliotheken wie den folgenden abhängig:

Viele Java-Anwendungen und -Frameworks verwenden diese Bibliotheken direkt oder transitiv, was zu Versionskonflikten führt. Abhängigkeits-Manager wie Maven und Gradle lösen alle Abhängigkeiten auf, sodass jeweils nur eine einzelne Version der Abhängigkeiten im Klassenpfad vorhanden ist. Die aufgelöste Abhängigkeitsversion ist jedoch unter Umständen nicht mit allen Consumern dieser Abhängigkeit in Ihrer Anwendung kompatibel. Weitere Informationen finden Sie in der Einführung in den Abhängigkeitsmechanismus aus der Maven-Dokumentation sowie unter Grundlegendes zur Abhängigkeitsauflösung aus der Gradle-Dokumentation.

Die API-Inkompatibilität direkter Abhängigkeiten führt zu Kompilierungsfehlern. Inkompatibilitäten aufgrund von Diamantabhängigkeiten (Diamond dependency) führen in der Regel zu Laufzeitfehlern wie NoClassDefFoundError oder NoSuchMethodError oder zu LinkageError. Nicht alle Bibliotheken halten sich streng an die semantische Versionierung, und Breaking Changes werden manchmal innerhalb der gleichen Hauptversion eingeführt.

Diagnostizieren von Problemen im Zusammenhang mit Versionskonflikten

In den folgenden Abschnitten werden Methoden zum Diagnostizieren von Problemen mit versionskonflikten beschrieben.

Verwenden des Azure SDK für Java-Buildtools

Das Azure SDK für Java-Buildtool, das in "Erste Schritte mit Azure SDK" und Apache Maven eingeführt wurde, hilft bei der Identifizierung häufig auftretender Probleme. Es wird empfohlen, dieses Buildtool zu Ihrem Projekt hinzuzufügen und auszuführen, indem Sie das azure:run Maven-Ziel zu Ihrem regulären Buildprozess hinzufügen. Mit der entsprechenden Konfiguration können Sie Abhängigkeitskonflikte proaktiver identifizieren und lösen, bevor sie zur Laufzeit zu Problemen werden.

Anzeigen einer Abhängigkeitsstruktur

Führen Sie mvn dependency:tree oder gradle dependencies --scan aus, um die vollständige Abhängigkeitsstruktur für Ihre Anwendung anzuzeigen – einschließlich Versionsnummern. mvn dependency:tree -Dverbose enthält weitere Informationen, kann aber irreführend sein. Weitere Informationen finden Sie in der Maven-Dokumentation unter Apache Maven Dependency Tree . Beachten Sie für jede Bibliothek, die Sie vermuten, einen Versionskonflikt, die Versionsnummer, und bestimmen Sie, welche Komponenten davon abhängig sind.

Die Abhängigkeitsauflösung in Entwicklungs- und Produktionsumgebungen funktioniert möglicherweise unterschiedlich. Bei Verwendung benutzerdefinierter Abhängigkeiten müssen Apache Spark, Apache Flink, Databricks und IDE-Plug-Ins zusätzlich konfiguriert werden. Außerdem verfügen sie unter Umständen über eigene Versionen von Azure-Clientbibliotheken oder allgemeinen Komponenten. Weitere Informationen finden Sie in den folgenden Artikeln:

Weitere Informationen zur Konfliktlösung in solchen Umgebungen finden Sie im Abschnitt Erstellen einer fat-JAR-Datei weiter unten in diesem Artikel.

Konfigurieren von Azure Functions

Die interne Abhängigkeitsversion in Azure Functions (nur mit Java 8) hat Vorrang vor einer vom Benutzer bereitgestellten Version. Diese Abhängigkeit führt zu Versionskonflikten, insbesondere bei Jackson, Netty und Reactor.

Legen Sie zur Behebung dieses Problems die Umgebungsvariable FUNCTIONS_WORKER_JAVA_LOAD_APP_LIBS auf true oder 1 fest. Aktualisieren Sie die Azure Functions-Tools (v2 oder v3) auf die neueste Version.

Hinweis

Diese Konfiguration gilt nur für Azure Functions mit Java 8. Für Azure Functions mit Java 11 ist keine spezielle Konfiguration erforderlich.

Konfigurieren von Apache Spark

Das Azure SDK für Java unterstützt mehrere Versionen von Jackson, aber manchmal können Probleme auftreten, je nach Buildtools und dessen Anordnung der Abhängigkeitsauflösung. Ein gutes Beispiel für dieses Problem ist apache Spark, Version 3.0.0 und höher, die von Jackson 2.10 abhängt. Während es mit dem Azure SDK für Java kompatibel ist, entdecken Entwickler häufig, dass stattdessen eine neuere Version von Jackson verwendet wird, was zu Inkompatibilitäten führt. Um dieses Problem zu beheben, sollten Sie eine bestimmte Version von Jackson anheften (eine, die mit Spark kompatibel ist). Weitere Informationen finden Sie im Abschnitt "Support für mehrere Jackson-Versionen " in diesem Artikel.

Wenn Sie frühere Versionen von Spark verwenden oder eine andere Bibliothek, die Sie verwenden, eine noch frühere Version von Jackson erfordert, die das Azure SDK für Java nicht unterstützt, lesen Sie diesen Artikel weiter, um mögliche Abhilfemaßnahmen zu finden.

Erkennen der Laufzeitversion von Jackson

In Azure Core 1.21.0 wurden eine Laufzeiterkennung und eine bessere Diagnose der Jackson-Laufzeitversion hinzugefügt.

Wenn im Zusammenhang mit der Jackson-API LinkageError (oder eine der zugehörigen Unterklassen) angegeben ist, überprüfen Sie die Meldung der Ausnahme auf Informationen zur Laufzeitversion. Beispiel: 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

Suchen Sie nach Warnungs- und Fehlerprotokollen von JacksonVersion. Weitere Informationen finden Sie unter Konfigurieren der Protokollierung im Azure SDK für Java. Beispiel: [main] ERROR com.azure.core.implementation.jackson.JacksonVersion - Version '2.9.0' of package 'jackson-core' is not supported (too old), please upgrade.

Hinweis

Überprüfen Sie, ob alle Jackson-Pakete dieselbe Version haben.

Eine Liste der Pakete, die vom Azure SDK und den unterstützten Jackson-Versionen verwendet werden, finden Sie im Abschnitt "Support für mehrere Jackson-Versionen ".

Behandeln von Problemen im Zusammenhang mit Versionskonflikten

In den folgenden Abschnitten erfahren Sie, wie Sie Probleme im Zusammenhang mit Versionskonflikten behandeln.

Verwenden der Azure SDK-BOM

Verwenden Sie die neueste stabile Azure SDK-BOM, und geben Sie in Ihrer POM-Datei keine Azure SDK- und Abhängigkeitsversionen an. Verwenden Sie ggf. die Azure Spring Boot-BOM.

Die in der Azure SDK-BOM aufgeführten Abhängigkeiten werden gründlich getestet, um Abhängigkeitskonflikte zu vermeiden.

Vermeiden unnötiger Abhängigkeiten

Entfernen Sie Abhängigkeiten, wenn möglich. Manchmal verfügt eine Anwendung über Abhängigkeiten von mehreren Bibliotheken, die im Wesentlichen die gleichen Funktionen bieten. Solche unnötigen Abhängigkeiten machen Anwendungen anfällig für Sicherheitsrisiken und können Versionskonflikte sowie Support- und Wartungskosten verursachen.

Aktualisieren von Abhängigkeitsversionen

Wenn der Wechsel zur neuesten Azure SDK-BOM nicht hilfreich ist, identifizieren Sie die Bibliotheken, die Konflikte verursachen, und die Komponenten, die sie verwenden. (Weitere Informationen finden Sie unter Anzeigen eines Abschnitts der Abhängigkeitsstruktur weiter oben in diesem Artikel.) Versuchen Sie, auf eine neuere Version zu aktualisieren, die vor Sicherheitsrisiken schützt, und bietet häufig neue Features, Leistungsverbesserungen und Fehlerbehebungen.

Vermeiden Sie ein Downgrade der Azure SDK-Version, da Ihre Anwendung dadurch möglicherweise bekannten Sicherheitsrisiken und Problemen ausgesetzt wird.

Verwenden von Shading für Bibliotheken

Manchmal gibt es keine funktionierende Kombination von Bibliotheken. In diesem Fall hilft unter Umständen nur noch Shading.

Hinweis

Die Schattierung hat erhebliche Nachteile: Es erhöht die Paketgröße und die Anzahl der Klassen auf dem Klassenpfad, macht die Codenavigation und das Debuggen hart, verschiebt JNI-Code nicht, bricht Spiegelung und kann unter anderem Codelizenzen verletzen. Es sollte nur verwendet werden, wenn alle anderen Optionen ausgeschöpft sind.

Mithilfe der Schattierung können Sie Abhängigkeiten innerhalb eines JAR zur Erstellungszeit einschließen, dann Pakete umbenennen und Anwendungscode aktualisieren, um den Code am schattierten Speicherort zu verwenden. Durch Diamantabhängigkeit bedingte Konflikte sind nicht mehr relevant, da es zwei verschiedene Exemplare einer Abhängigkeit gibt. Sie können Shading für eine Bibliothek mit einer in Konflikt stehenden transitiven Abhängigkeit oder einer direkten Anwendungsabhängigkeit verwenden:

  • Transitive Abhängigkeitskonflikt: Beispielsweise erfordert die Drittanbieterbibliothek A Jackson 2.9, die Azure-SDKs nicht unterstützen, und es ist nicht möglich, zu aktualisieren A. Erstellen Sie ein neues Modul, das A enthält und Jackson 2.9 (sowie optional weitere Abhängigkeiten von A) mittels Shading verlagert.
  • Anwendungsabhängigkeitskonflikt: Ihre Anwendung verwendet Jackson 2.9 direkt. Während Sie daran arbeiten, Ihren Code zu aktualisieren, können Sie Jackson 2.9 stattdessen in ein neues Modul mit verschobenen Jackson-Klassen schattieren und verschieben.

Hinweis

Durch die Erstellung einer fat-JAR-Datei mit verlagerten Jackson-Klassen wird in diesen Beispielen kein Versionskonflikt gelöst, sondern nur eine einzelne Shading-Version von Jackson erzwungen.

Erstellen einer fat-JAR-Datei

Umgebungen wie Databricks und Apache Spark verfügen über eine benutzerdefinierte Abhängigkeitsverwaltung und stellen gängige Bibliotheken wie etwa Jackson bereit. Um Konflikte mit bereitgestellten Bibliotheken zu vermeiden, empfiehlt sich ggf. die Erstellung einer fat-JAR-Datei, die alle Abhängigkeiten enthält. Weitere Informationen finden Sie unter Shade-Plug-In von Apache Maven. In vielen Fällen lässt sich das Problem durch Verlagern von Jackson-Klassen (com.fasterxml.jackson) beheben. Manchmal verfügen solche Umgebungen auch über eigene Version von Azure SDKs, sodass Sie möglicherweise den Namespace com.azure verlagern müssen, um Versionskonflikte zu umgehen.

Informieren über kompatible Abhängigkeitsversionen

Informationen zu azure-corespezifischen Abhängigkeiten und deren Versionen finden Sie unter azure-core im Maven Central Repository. Die folgende Tabelle enthält einige allgemeine Aspekte:

Abhängigkeit Unterstützte Versionen
Jackson 2.10.0 und neuere Nebenversionen sind kompatibel. Weitere Informationen finden Sie im Abschnitt "Support für mehrere Jackson-Versionen ".
SLF4J 1.7.*
netty-tcnative-boringssl-static 2.0.*
netty-common 4.1.*
reactor-core 3.X.*. Die Nummern der Haupt- und Nebenversionen müssen exakt den Nummern entsprechen, von denen Ihre azure-core-Version abhängt. Weitere Informationen finden Sie in der Veraltungsrichtlinie von Project Reactor.

Unterstützung für mehrere Jackson-Versionen

Das Azure SDK für Java unterstützt das Arbeiten mit einer Reihe von Jackson-Versionen. Die niedrigste unterstützte Version ist Jackson 2.10.0. Das Azure SDK für Java-Clientbibliotheken passen ihre Konfiguration und die Jackson-Verwendung abhängig von der Version an, die zur Laufzeit erkannt wird. Diese Anpassung ermöglicht eine höhere Kompatibilität mit älteren Versionen des Spring-Frameworks, Apache Spark und anderen gängigen Umgebungen. Anwendungen können Jackson-Versionen (auf 2.10.0 oder höher) herunterstufen, ohne das Azure SDK für Java-Clientbibliotheken zu unterbrechen.

Hinweis

Die Verwendung alter Versionen von Jackson kann Anwendungen bekannten Sicherheitsrisiken und Problemen zur Verfügung stellen. Weitere Informationen finden Sie in der Liste der bekannten Sicherheitsrisiken für Jackson-Bibliotheken.

Stellen Sie beim Anheften einer bestimmten Version von Jackson sicher, dass Sie dies für alle Module tun, die von Azure SDK verwendet werden, die in der folgenden Liste angezeigt werden:

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

Migration von Jackson zu azure-json

Azure-Clientbibliotheken für Java befinden sich im Prozess der Migration zu Azure-JSON, die nicht von Drittanbieterkomponenten abhängig ist und freigegebene Grundtypen, Abstraktionen und Hilfsprogramme für JSON bietet.

Umgebungen wie Apache Spark, Apache Flink und Databricks können ältere Versionen enthalten, von azure-core denen noch nicht abhängig sind azure-json. Wenn Sie daher neuere Versionen von Azure-Bibliotheken in solchen Umgebungen verwenden, erhalten Sie möglicherweise Ähnliche Fehler java.lang.NoClassDefFoundError: com/azure/json/JsonSerializable. Sie können diesen Fehler beheben, indem Sie eine explizite Abhängigkeit hinzufügen azure-json.

Nächste Schritte

Nachdem Sie nun mit Abhängigkeitsversionskonflikten und deren Behandlung vertraut sind, können Sie sich unter Abhängigkeitsverwaltung für Java darüber informieren, wie sich solche Konflikte am besten verhindern lassen.