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 diamond zwykle powoduje błędy środowiska uruchomieniowego, takie jak NoClassDefFoundError, NoSuchMethodError lub inne błędy LinkageError. Nie wszystkie biblioteki ściśle przestrzegają semantycznego przechowywania wersji, a zmiany powodujące niezgodność 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
docelowego narzędzia 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 mvn dependency:tree
polecenie lub gradle dependencies --scan
, aby wyświetlić pełne drzewo zależności dla aplikacji 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 podejrzanej biblioteki wystąpił konflikt wersji, zanotuj jego 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:
- Tworzenie pakietów zależności aplikacji dla platformy Apache Spark
- Konfiguracja projektu dla narzędzia Apache Flink
- Jak poprawnie zaktualizować bibliotekę Maven w usłudze Databricks dla usługi Databricks
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ścią. Aby rozwiązać ten problem, należy przypiąć określoną wersję jacksona (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 innej używanej biblioteki wymaga jeszcze wcześniejszej wersji narzędzia Jackson, której zestaw Azure SDK dla języka Java nie obsługuje, zapoznaj się z tym artykułem, aby uzyskać możliwe kroki ograniczania ryzyka.
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. Na 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 rejestrowania w zestawie Azure SDK dla języka 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 modelu BOM zestawu Azure SDK i nie określaj wersji zestawu Azure SDK i 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 uwidaczniają aplikacje w przypadku luk w zabezpieczeniach, konfliktów wersji oraz kosztów 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 Wyświetl sekcję 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 ona uwidaczniać aplikację w znanych lukach w zabezpieczeniach i problemach.
Biblioteki cieniowania
Czasami nie ma kombinacji bibliotek, które współpracują ze sobą, a cieniowanie pojawia się w ostateczności.
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 rombu nie jest już problemem, ponieważ istnieją dwie różne kopie zależności. Możesz zacienić bibliotekę, która ma zależność przechodnią lub zależność aplikacji bezpośredniej, zgodnie z opisem na poniższej liście:
- Konflikt zależności przechodnich: na przykład biblioteka innej firmy wymaga biblioteki
A
Jackson 2.9, której zestawy SDK platformy Azure nie obsługują i nie można zaktualizowaćA
elementu . Utwórz nowy moduł, który zawieraA
i odcienie (przeniesienie) Jackson 2.9 i, opcjonalnie, inne zależności programuA
. - 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.
Tworzenie tłuszczu 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 mają również własną wersję zestawów SDK platformy Azure, więc możesz być zmuszony do przeniesienia com.azure
przestrzeni nazw w celu obejścia konfliktów wersji.
Omówienie zgodnych wersji zależności
Aby uzyskać informacje o azure-core
zależnościach specyficznych dla środowiska i ich wersjach, zobacz azure-core w repozytorium centralnym maven. W poniższej tabeli przedstawiono pewne ogólne zagadnienia:
Dependency | Obsługiwane wersje |
---|---|
Jackson | Wersje 2.10.0 i nowsze wersje pomocnicze są zgodne. Aby uzyskać więcej informacji, zobacz sekcję Obsługa wielu wersji jacksona. |
SLF4J | 1.7.* |
netty-tcnative-boringssl-static | 2.0.* |
netty-common | 4.1.* |
rdzeń reaktora | 3.X.* — numery wersji głównych i pomocniczych muszą dokładnie odpowiadać tym, od których zależy Twoja azure-core wersja. Aby uzyskać więcej informacji, zobacz zasady Project Reactor dotyczące wycofywania. |
Obsługa wielu wersji Jackson
Zestaw Azure SDK dla języka Java 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ą konfigurację i użycie jacksona w zależności od wersji wykrytej w czasie wykonywania. 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 jacksona może uwidaczniać aplikacje znanymi lukami w zabezpieczeniach i problemami. 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 pliku azure-json
Biblioteki klienta platformy Azure dla języka Java są w trakcie migracji do pliku azure-json, który nie zależy od żadnych składników innych firm i oferuje współużytkowane elementy pierwotne, abstrakcji i pomocników 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-json
programu . 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-json
elementu .
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.