Felsöka konflikter i beroendeversion
I den här artikeln beskrivs konflikter i beroendeversioner och hur du felsöker dem.
Azure-klientbibliotek för Java är beroende av populära bibliotek från tredje part, till exempel följande:
Många Java-program och ramverk använder dessa bibliotek direkt eller transitivt, vilket leder till versionskonflikter. Beroendehanterare som Maven och Gradle löser alla beroenden så att det bara finns en enda version av varje beroende på klassökvägen. Det är dock inte garanterat att den lösta beroendeversionen är kompatibel med alla användare av det beroendet i ditt program. Mer information finns i Introduktion till beroendemekanismen i Maven-dokumentationen och Förstå beroendematchning i Gradle-dokumentationen.
API:ets inkompatibilitet för direkta beroenden resulterar i kompileringsfel. Inkompatibilitet för diamantberoende resulterar vanligtvis i körningsfel som NoClassDefFoundError, NoSuchMethodError eller annan LinkageError. Alla bibliotek följer inte strikt semantisk versionshantering, och icke-bakåtkompatibla ändringar sker ibland i samma huvudversion.
Diagnostisera problem med versionsmatchning
I följande avsnitt beskrivs metoder för hur du diagnostiserar problem med versionsmatchningsfel.
Använda Azure SDK för Java-kompileringsverktyget
Azure SDK för Java-byggverktyget, som introducerades i Kom igång med Azure SDK och Apache Maven, hjälper till att identifiera vanliga problem. Vi rekommenderar att du lägger till det här byggverktyget i projektet och kör det genom att lägga till azure:run
Maven-målet i din vanliga byggprocess. Med rätt konfiguration kan du identifiera och lösa beroendekonflikter mer proaktivt innan de blir problem vid körning.
Visa ett beroendeträd
Kör mvn dependency:tree
eller gradle dependencies --scan
för att visa det fullständiga beroendeträdet för ditt program med versionsnummer. mvn dependency:tree -Dverbose
ger mer information, men kan vara missvisande. Mer information finns i Apache Maven Dependency Tree i Maven-dokumentationen. Anteckna versionsnumret för varje bibliotek som du misstänker har en versionskonflikt och ta reda på vilka komponenter som är beroende av det.
Beroendematchning i utvecklings- och produktionsmiljöer kan fungera annorlunda. Apache Spark-, Apache Flink-, Databricks- och IDE-plugin-program behöver extra konfiguration för anpassade beroenden. De kan också ta med sina egna versioner av Azure-klientbibliotek eller vanliga komponenter. Mer information finns i följande artiklar:
- Paketera programmets beroenden för Apache Spark
- Projektkonfiguration för Apache Flink
- Så här uppdaterar du ett Maven-bibliotek i Databricks för Databricks korrekt
Mer information om konfliktlösning i sådana miljöer finns i avsnittet Skapa en fet JAR senare i den här artikeln.
Konfigurera Azure Functions
Den interna beroendeversionen för Azure Functions (endast Java 8) har företräde framför en användarversion. Det här beroendet orsakar versionskonflikter, särskilt med Jackson, Netty och Reactor.
Lös problemet genom att ange FUNCTIONS_WORKER_JAVA_LOAD_APP_LIBS
miljövariabeln till true
eller 1
. Se till att uppdatera Azure Function Tools (v2 eller v3) till den senaste versionen.
Kommentar
Den här konfigurationen gäller endast för Azure Functions som kör Java 8. Funktioner som kör Java 11 behöver inte någon särskild konfiguration.
Konfigurera Apache Spark
Azure SDK för Java har stöd för flera versioner av Jackson, men problem kan ibland uppstå beroende på din byggverktyg och dess beroendematchningsordning. Ett bra exempel på det här problemet är med Apache Spark, version 3.0.0 och senare, som är beroende av Jackson 2.10. Även om det är kompatibelt med Azure SDK för Java upptäcker utvecklare ofta att en nyare version av Jackson används i stället, vilket resulterar i inkompatibiliteter. För att åtgärda det här problemet bör du fästa en specifik version av Jackson (en som är kompatibel med Spark). Mer information finns i avsnittet Support för flera Jackson-versioner i den här artikeln.
Om du använder tidigare versioner av Spark, eller om ett annat bibliotek som du använder kräver en ännu tidigare version av Jackson som Azure SDK för Java inte stöder, fortsätter du att läsa den här artikeln för möjliga åtgärdssteg.
Identifiera Jackson-körningsversion
I Azure Core 1.21.0 lade vi till körningsidentifiering och bättre diagnostik av Jackson-körningsversionen.
Om du ser LinkageError
(eller någon av dess underklasser) som är relaterade till Jackson-API:et kontrollerar du meddelandet om undantaget för körningsversionsinformation. Till exempel: 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
Leta efter varnings- och felloggar från JacksonVersion
. Mer information finns i Konfigurera loggning i Azure SDK för Java. Till exempel: [main] ERROR com.azure.core.implementation.jackson.JacksonVersion - Version '2.9.0' of package 'jackson-core' is not supported (too old), please upgrade.
Kommentar
Kontrollera att alla Jackson-paket har samma version.
Listan över paket som används av Azure SDK och de Jackson-versioner som stöds finns i avsnittet Stöd för flera Jackson-versioner .
Åtgärda problem med versionsmatchning
I följande avsnitt beskrivs hur du åtgärdar problem med versionsmatchningsfel.
Använda Azure SDK BOM
Använd den senaste stabila Azure SDK-bommen och ange inte Azure SDK och beroendeversioner i POM-filen. När det är tillämpligt använder du Azure Spring Boot BOM.
Beroendena som anges i Azure SDK-bommen testas noggrant för att undvika beroendekonflikter.
Undvik onödiga beroenden
Ta bort beroenden om du kan. Ibland har ett program beroenden på flera bibliotek som ger i stort sett samma funktioner. Sådana onödiga beroenden utsätter program för säkerhetsrisker, versionskonflikter och support- och underhållskostnader.
Uppdatera beroendeversioner
Om det inte hjälper att växla till den senaste Azure SDK-bommen kan du identifiera de bibliotek som orsakar konflikter och de komponenter som använder dem. (Mer information finns i Visa ett beroendeträdsavsnitt tidigare i den här artikeln.) Prova att uppdatera till en nyare version som skyddar mot säkerhetsrisker och ofta innehåller nya funktioner, prestandaförbättringar och felkorrigeringar.
Undvik att nedgradera Azure SDK-versionen eftersom den kan utsätta ditt program för kända sårbarheter och problem.
Skuggbibliotek
Ibland finns det ingen kombination av bibliotek som fungerar tillsammans, och skuggning kommer som den sista utvägen.
Kommentar
Skuggning har betydande nackdelar: det ökar paketstorleken och antalet klasser på klassökvägen, det gör kodnavigering och felsökning svårt, flyttar inte JNI-kod, bryter reflektion och kan bryta mot kodlicenser bland annat. Den bör endast användas när andra alternativ är uttömda.
Med skuggning kan du inkludera beroenden i en JAR vid byggtiden, byta namn på paket och uppdatera programkoden så att koden används på den skuggade platsen. Diamantberoendekonflikter är inte längre ett problem eftersom det finns två olika kopior av ett beroende. Du kan skugga ett bibliotek som har ett transitivt beroende i konflikt eller ett direkt programberoende enligt beskrivningen i följande lista:
- Transitiv beroendekonflikt: Till exempel kräver bibliotek
A
från tredje part Jackson 2.9, som Azure SDK:er inte stöder, och det går inte att uppdateraA
. Skapa en ny modul, som innehållerA
och nyanser (flyttar) Jackson 2.9 och, om du vill, andra beroenden avA
. - Programberoendekonflikt: Programmet använder Jackson 2.9 direkt. Medan du arbetar med att uppdatera koden kan du skugga och flytta Jackson 2.9 till en ny modul med flyttade Jackson-klasser i stället.
Kommentar
Att skapa fet JAR med flyttade Jackson-klasser löser inte en versionskonflikt i dessa exempel – det tvingar bara fram en enda skuggad version av Jackson.
Skapa en fet JAR
Miljöer som Databricks eller Apache Spark har anpassad beroendehantering och tillhandahåller vanliga bibliotek som Jackson. För att undvika konflikter med de bibliotek som tillhandahålls kanske du vill skapa en fet JAR som innehåller alla beroenden. Mer information finns i Apache Maven Shade Plugin. I många fall minskar problemet genom att flytta Jackson-klasser (com.fasterxml.jackson
). Ibland tar sådana miljöer också med sig en egen version av Azure SDK:er, så du kan bli tvungen att flytta com.azure
namnområdet för att kringgå versionskonflikter.
Förstå kompatibla beroendeversioner
Information om azure-core
-specifika beroenden och deras versioner finns i azure-core på Den centrala Maven-lagringsplatsen. Följande tabell visar några allmänna överväganden:
Dependency | Versioner som stöds |
---|---|
Jackson | 2.10.0 och senare delversioner är kompatibla. Mer information finns i avsnittet Support för flera Jackson-versioner . |
SLF4J | 1.7.* |
netty-tcnative-boringssl-static | 2.0.* |
netty-common | 4.1.* |
reaktorkärna | 3.X.* – Huvud- och delversionsnummer måste exakt matcha de som din azure-core version är beroende av. Mer information finns i Project Reactor-principen om utfasningar. |
Stöd för flera Jackson-versioner
Azure SDK för Java stöder arbete med en rad Olika Jackson-versioner. Den version som stöds lägst är Jackson 2.10.0. Azure SDK för Java-klientbibliotek justerar sin konfiguration och Jackson-användning beroende på vilken version som identifieras vid körning. Den här justeringen möjliggör större kompatibilitet med äldre versioner av Spring-ramverket, Apache Spark och andra vanliga miljöer. Program kan nedgradera Jackson-versioner (till 2.10.0 eller senare) utan att bryta Azure SDK för Java-klientbibliotek.
Kommentar
Om du använder gamla versioner av Jackson kan program utsättas för kända sårbarheter och problem. Mer information finns i listan över kända sårbarheter för Jackson-bibliotek.
När du fäster en specifik version av Jackson måste du göra det för alla moduler som används av Azure SDK, som visas i följande lista:
jackson-annotations
jackson-core
jackson-databind
jackson-dataformat-xml
jackson-datatype-jsr310
Migrering från Jackson till azure-json
Azure-klientbibliotek för Java håller på att migreras till azure-json, som inte är beroende av komponenter från tredje part, och erbjuder delade primitiver, abstraktioner och hjälpverktyg för JSON.
Miljöer som Apache Spark, Apache Flink och Databricks kan medföra äldre versioner av som ännu inte är beroende azure-json
av azure-core
. När du använder nyare versioner av Azure-bibliotek i sådana miljöer kan du därför få fel som liknar java.lang.NoClassDefFoundError: com/azure/json/JsonSerializable
. Du kan åtgärda det här felet genom att lägga till ett explicit beroende av azure-json
.
Nästa steg
Nu när du är bekant med beroendeversionskonflikter och hur du felsöker dem kan du läsa Beroendehantering för Java för information om det bästa sättet att förhindra dem.