Udostępnij za pośrednictwem


Rozwiązywanie problemów z konfliktami wersji zależności

W tym artykule opisano konflikty wersji zależności i sposób ich rozwiązywania.

Biblioteki klienckie platformy Azure dla języka Java zależą od popularnych bibliotek innych firm, takich jak następujące:

Wiele aplikacji i struktur Java używa tych bibliotek bezpośrednio lub przechodnio, co prowadzi do konfliktów wersji. Menedżerowie zależności, tacy jak Maven i Gradle , rozwiązują wszystkie zależności, tak aby istniała tylko jedna wersja każdej zależności na ścieżce klas. Nie ma jednak gwarancji, że rozpoznana wersja zależności jest zgodna ze wszystkimi użytkownikami tej zależności w aplikacji. Aby uzyskać więcej informacji, zobacz Wprowadzenie do mechanizmu zależności w dokumentacji narzędzia Maven i Opis rozwiązywania zależności w dokumentacji narzędzia Gradle.

Niezgodność interfejsu API bezpośrednich zależności powoduje błędy kompilacji. Niezgodność zależności diamentowych zwykle powoduje błędy środowiska uruchomieniowego, takie jak NoClassDefFoundError, NoSuchMethodError lub inne LinkageError. Nie wszystkie biblioteki ściśle przestrzegają semantycznego wersjonowania, a zmiany wprowadzające niezgodności czasami występują w tej samej wersji głównej.

Diagnozowanie problemów z niezgodnością wersji

W poniższych sekcjach opisano metody diagnozowania problemów z niezgodnością wersji.

Korzystanie z zestawu Azure SDK dla narzędzia kompilacji języka Java

Narzędzie do kompilacji zestawu Azure SDK dla języka Java wprowadzone w temacie Rozpoczynanie pracy z zestawem Azure SDK i narzędziem Apache Maven ułatwia identyfikowanie często napotykanych problemów. Zalecamy dodanie tego narzędzia kompilacji do projektu i uruchomienie go przez dodanie azure:run celu Maven do zwykłego procesu kompilacji. Dzięki odpowiedniej konfiguracji można łatwiej identyfikować i rozwiązywać konflikty zależności, zanim staną się one problemami w czasie wykonywania.

Wyświetlanie drzewa zależności

Uruchom polecenie mvn dependency:tree lub gradle dependencies --scan, aby wyświetlić pełne drzewo zależności dla aplikacji wraz z numerami wersji. mvn dependency:tree -Dverbose zawiera więcej informacji, ale może być mylące. Aby uzyskać więcej informacji, zobacz Apache Maven Dependency Tree (Drzewo zależności apache Maven ) w dokumentacji narzędzia Maven. Dla każdej biblioteki, w której podejrzewasz konflikt wersji, zanotuj jej numer wersji i określ, które składniki zależą od niej.

Rozwiązywanie zależności w środowiskach deweloperskich i produkcyjnych może działać inaczej. Wtyczki Apache Spark, Apache Flink, Databricks i IDE wymagają dodatkowej konfiguracji dla niestandardowych zależności. Mogą również przynieść własne wersje bibliotek klienckich platformy Azure lub typowe składniki. Aby uzyskać więcej informacji, zobacz następujące artykuły:

Aby uzyskać więcej informacji na temat rozwiązywania konfliktów w takich środowiskach, zobacz sekcję Tworzenie tłuszczu JAR w dalszej części tego artykułu.

Konfigurowanie usługi Azure Functions

Wewnętrzna wersja zależności w usłudze Azure Functions (tylko w środowisku Java 8) ma pierwszeństwo przed wersją udostępnioną przez użytkownika. Ta zależność powoduje konflikty wersji, zwłaszcza w przypadku Jackson, Netty i Reactor.

Aby rozwiązać ten problem, ustaw zmienną FUNCTIONS_WORKER_JAVA_LOAD_APP_LIBS środowiskową na true lub 1. Pamiętaj, aby zaktualizować narzędzia funkcji platformy Azure (w wersji 2 lub 3) do najnowszej wersji.

Uwaga

Ta konfiguracja dotyczy tylko usługi Azure Functions z uruchomionym językiem Java 8. Funkcje z uruchomionym językiem Java 11 nie wymagają specjalnej konfiguracji.

Konfigurowanie platformy Apache Spark

Zestaw Azure SDK dla języka Java obsługuje wiele wersji jacksona, ale czasami mogą wystąpić problemy w zależności od narzędzi kompilacji i kolejności rozwiązywania zależności. Dobrym przykładem tego problemu jest platforma Apache Spark w wersji 3.0.0 lub nowszej, która zależy od jacksona 2.10. Chociaż jest ona zgodna z zestawem Azure SDK dla języka Java, deweloperzy często odkrywają, że używana jest nowsza wersja Jacksona, co skutkuje niezgodnościami. Aby rozwiązać ten problem, należy ustalić konkretną wersję Jackson (zgodną z platformą Spark). Aby uzyskać więcej informacji, zobacz sekcję Pomoc techniczna dla wielu wersji jacksona w tym artykule.

Jeśli używasz wcześniejszych wersji platformy Spark lub jeśli inna używana biblioteka wymaga jeszcze wcześniejszej wersji Jackson, której nie obsługuje Azure SDK dla języka Java, przeczytaj ten artykuł, aby poznać możliwe rozwiązania problemu.

Wykrywanie wersji środowiska uruchomieniowego Jackson

W usłudze Azure Core 1.21.0 dodaliśmy wykrywanie środowiska uruchomieniowego i lepszą diagnostykę wersji środowiska uruchomieniowego Jackson.

Jeśli widzisz LinkageError (lub dowolną z jego podklas) powiązaną z interfejsem API Jacksona, sprawdź komunikat wyjątku dla informacji o wersji środowiska uruchomieniowego. Przykład: 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

Poszukaj dzienników ostrzeżeń i błędów z witryny JacksonVersion. Aby uzyskać więcej informacji, zobacz Konfigurowanie logowania w pakiecie Azure SDK dla Java. Przykład: [main] ERROR com.azure.core.implementation.jackson.JacksonVersion - Version '2.9.0' of package 'jackson-core' is not supported (too old), please upgrade.

Uwaga

Sprawdź, czy wszystkie pakiety Jackson mają tę samą wersję.

Aby uzyskać listę pakietów używanych przez zestaw Azure SDK i obsługiwane wersje Jacksona, zobacz sekcję Pomoc techniczna dla wielu wersji Jacksona.

Eliminowanie problemów z niezgodnością wersji

W poniższych sekcjach opisano sposób rozwiązywania problemów z niezgodnością wersji.

Korzystanie z modelu BOM zestawu Azure SDK

Używaj najnowszej stabilnej wersji Azure SDK BOM i nie określaj wersji Azure SDK ani zależności w pliku POM. Jeśli ma to zastosowanie, użyj rozwiązania Azure Spring Boot BOM.

Zależności wymienione w zestawie Azure SDK BOM są testowane rygorystycznie, aby uniknąć konfliktów zależności.

Unikaj niepotrzebnych zależności

Jeśli to możliwe, usuń zależności. Czasami aplikacja ma zależności od wielu bibliotek, które zapewniają zasadniczo te same funkcje. Takie niepotrzebne zależności narażają aplikacje na luki w zabezpieczeniach, konflikty wersji oraz koszty obsługi i konserwacji.

Aktualizowanie wersji zależności

Jeśli przejście do najnowszego modelu BOM zestawu Azure SDK nie pomoże, zidentyfikuj biblioteki powodujące konflikty i składniki, które ich używają. (Aby uzyskać więcej informacji, zobacz sekcję Wyświetlanie drzewa zależności we wcześniejszej części tego artykułu). Spróbuj zaktualizować do nowszej wersji, która chroni przed lukami w zabezpieczeniach i często wprowadza nowe funkcje, ulepszenia wydajności i poprawki błędów.

Unikaj obniżania wersji zestawu Azure SDK, ponieważ może to narażać aplikację na znane luki w zabezpieczeniach i problemy techniczne.

Biblioteki cieniowania

Czasami nie ma kombinacji bibliotek, które współpracują ze sobą, wtedy stosujemy cieniowanie jako ostateczność.

Uwaga

Cieniowanie ma znaczące wady: zwiększa rozmiar pakietu i liczbę klas na ścieżce klasy, sprawia, że nawigacja kodu i debugowanie są trudne, nie przenosi kodu JNI, przerywa odbicie i może naruszać między innymi licencje kodu. Należy go używać tylko po wyczerpaniu innych opcji.

Cieniowanie umożliwia uwzględnianie zależności w pliku JAR w czasie kompilacji, a następnie zmienianie nazw pakietów i aktualizowanie kodu aplikacji w celu użycia kodu w zacienionej lokalizacji. Konflikt zależności diamentowej nie jest już problemem, ponieważ istnieją dwie różne wersje tej zależności. Możesz zakryć bibliotekę, która ma konfliktową zależność przechodnią lub bezpośrednią zależność aplikacji, jak opisano na poniższej liście:

  • Konflikt zależności przechodnich: na przykład biblioteka innej firmy wymaga Jackson 2.9, której zestawy SDK platformy Azure nie obsługują i nie ma możliwości aktualizacji A. Utwórz nowy moduł, który zawiera A i odcienie (przeniesienie) Jackson 2.9 i, opcjonalnie, inne zależności programu A.
  • Konflikt zależności aplikacji: Aplikacja korzysta bezpośrednio z usługi Jackson 2.9. Podczas pracy nad aktualizowaniem kodu możesz zamiast tego zacienić i przenieść jacksona 2.9 do nowego modułu z przeniesionymi klasami Jackson.

Uwaga

Tworzenie fat JAR z przeniesionymi klasami Jackson nie rozwiązuje konfliktu wersji w tych przykładach - wymusza tylko jedną zacieniowaną wersję Jacksona.

Utwórz fat JAR

Środowiska takie jak Databricks lub Apache Spark mają niestandardowe zarządzanie zależnościami i udostępniają typowe biblioteki, takie jak Jackson. Aby uniknąć konfliktu z dostarczonymi bibliotekami, możesz utworzyć gruby plik JAR zawierający wszystkie zależności. Aby uzyskać więcej informacji, zobacz Apache Maven Shade Plugin (Wtyczka apache Maven Shade Plugin). W wielu przypadkach przeniesienie klas Jacksona (com.fasterxml.jackson) ogranicza problem. Czasami takie środowiska dostarczają również własne wersje zestawów SDK platformy Azure, co może zmusić cię do przeniesienia przestrzeni nazw com.azure, aby obejść konflikty wersji.

Omówienie zgodnych wersji zależności

Aby uzyskać informacje o azure-corezależnościach specyficznych dla środowiska oraz ich wersji, odwiedź azure-core w repozytorium Maven Central. W poniższej tabeli przedstawiono pewne ogólne zagadnienia:

Zależność Obsługiwane wersje
Jackson Wersje 2.10.0 i nowsze wersje pomocnicze są zgodne. Aby uzyskać więcej informacji, zobacz sekcję Wsparcie dla wielu wersji Jacksona.
SLF4J 1.7.*
netty-tcnative-boringssl-static 2.0.*
netty-common (element wspólny) 4.1.*
rdzeń reaktora 3.X.* — numery wersji głównych i drugorzędnych muszą dokładnie odpowiadać tym, od których zależy Twoja azure-core wersja. Aby uzyskać więcej informacji, zapoznaj się z polityką Project Reactor dotyczącą wycofania.

Obsługa wielu wersji Jackson

Azure SDK dla Javy obsługuje pracę z wieloma wersjami Jacksona. Najniższa obsługiwana wersja to Jackson 2.10.0. Biblioteki klienckie zestawu Azure SDK dla języka Java dostosowują swoją konfigurację i użycie Jacksona w zależności od wykrytej wersji podczas działania programu. To dostosowanie umożliwia większą zgodność ze starszymi wersjami platformy Spring, platformy Apache Spark i innych typowych środowisk. Aplikacje mogą obniżyć wersję Jackson (do wersji 2.10.0 lub nowszej) bez przerywania działania zestawu Azure SDK dla bibliotek klienckich Języka Java.

Uwaga

Używanie starych wersji Jackson może narażać aplikacje na znane luki w zabezpieczeniach i problemy. Aby uzyskać więcej informacji, zobacz listę znanych luk w zabezpieczeniach bibliotek Jackson.

Podczas przypinania określonej wersji narzędzia Jackson upewnij się, że jest to możliwe dla wszystkich modułów używanych przez zestaw Azure SDK, które są wyświetlane na poniższej liście:

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

Migracja z Jacksona do azure-json

Biblioteki klienta platformy Azure dla języka Java są w trakcie migracji do azure-json, który nie zależy od żadnych komponentów innych firm i oferuje współdzielone podstawowe elementy, abstrakcje i funkcje pomocnicze dla formatu JSON.

Środowiska takie jak Apache Spark, Apache Flink i Databricks mogą przynieść starsze wersje azure-core , które jeszcze nie zależą od azure-jsonprogramu . W związku z tym w przypadku korzystania z nowszych wersji bibliotek platformy Azure w takich środowiskach mogą wystąpić błędy podobne do java.lang.NoClassDefFoundError: com/azure/json/JsonSerializable. Ten błąd można wyeliminować, dodając jawną zależność od azure-jsonelementu .

Następne kroki

Teraz, gdy znasz konflikty wersji zależności i sposoby ich rozwiązywania, zobacz Zarządzanie zależnościami dla języka Java , aby uzyskać informacje na temat najlepszego sposobu ich zapobiegania.