Устранение конфликтов версий зависимостей
В этой статье описываются конфликты версий зависимостей и способы их устранения.
Клиентские библиотеки Azure для Java зависят от популярных сторонних библиотек, таких как следующие:
Многие приложения и платформы Java используют эти библиотеки напрямую или транзитивно, что приводит к конфликтам версий. Диспетчеры зависимостей, например Maven и Gradle, разрешают все зависимости таким образом, чтобы существовала только одна версия каждой зависимости в определенном пути класса. Но разрешенная версия зависимости необязательно будет совместима со всеми потребителями такой зависимости в приложении. Дополнительные сведения см. во введении в механизм зависимостей в документации Maven и в описании разрешения зависимостей в документации Gradle.
Несовместимость API прямых зависимостей приводит к ошибкам компиляции. Несовместимость с ромбовидной зависимостью обычно приводит к сбоям во время выполнения, например к ошибкам NoClassDefFoundError, NoSuchMethodError или другим ошибкам LinkageError. Не все библиотеки строго следуют семантическому управлению версиями, и в одной основной версии могут присутствовать критические изменения.
Диагностика проблем с несовпадением версий
В следующих разделах описываются методы диагностики проблем несоответствия версий.
Использование средства сборки пакета SDK Azure для Java
Средство сборки пакета SDK Azure для Java, представленное в статье "Начало работы с пакетом SDK Azure" и Apache Maven, помогает выявить распространенные проблемы. Мы рекомендуем добавить это средство сборки в проект и запустить его, добавив целевой azure:run
объект Maven в обычный процесс сборки. С помощью соответствующей конфигурации можно выявлять и устранять конфликты зависимостей более упреждающим образом, прежде чем они становятся проблемами во время выполнения.
Просмотр дерева зависимостей
Выполните mvn dependency:tree
или gradle dependencies --scan
, чтобы отобразить полное дерево зависимостей для приложения (с номерами версий). mvn dependency:tree -Dverbose
предоставляет дополнительные сведения, но может вводить в заблуждение. Дополнительные сведения см. в разделе "Дерево зависимостей Apache Maven" в документации Maven. Для каждой библиотеки, подозреваемой в конфликте версий, обратите внимание на его номер версии и определите, какие компоненты зависят от него.
Разрешение зависимостей в средах разработки и рабочих средах может работать по-разному. Подключаемые модули Apache Spark, Apache Flink, Databricks и IDE требуют дополнительной настройки для пользовательских зависимостей. Они также могут внедрять собственные версии клиентских библиотек Azure или общих компонентов. Дополнительные сведения см. в следующих статьях:
- Объединение зависимостей приложений для Apache Spark
- Настройка проекта для Apache Flink
- Как правильно обновить библиотеку Maven в Databricks для Databricks
Дополнительные сведения о разрешении конфликтов в таких средах см. в разделе Создание "толстого" JAR далее в этой статье.
Настройка функций Azure
Версия внутренней зависимости для Функций Azure (работает только на Java 8) имеет приоритет над версией, предоставленной пользователем. Эта зависимость приводит к возникновению конфликтов версий, особенно с Jackson, Netty и Reactor.
Чтобы разрешить эту проблему, задайте для переменной среды FUNCTIONS_WORKER_JAVA_LOAD_APP_LIBS
значение true
или 1
. Обязательно обновите инструменты Функций Azure (версии 2 или 3) до последней версии.
Примечание.
Эта конфигурация применяется к Функциям Azure, работающим только с Java 8. Для Функций с Java 11 не требуется особая настройка.
Настройка Apache Spark
Пакет SDK Для Azure для Java поддерживает несколько версий Джексона, но иногда возникают проблемы в зависимости от средств сборки и порядка разрешения зависимостей. Хорошим примером этой проблемы является Apache Spark версии 3.0.0 и более поздней версии, которая зависит от Джексона 2.10. Хотя она совместима с пакетом SDK Azure для Java, разработчики часто обнаруживают, что вместо этого используется более поздняя версия Джексона, что приводит к несовместимости. Чтобы устранить эту проблему, следует закрепить определенную версию Джексона (совместимую с Spark). Дополнительные сведения см. в разделе "Поддержка нескольких версий Джексона " в этой статье.
Если вы используете более ранние версии Spark или если для другой библиотеки требуется еще более ранняя версия Джексона, которую пакет SDK Azure для Java не поддерживает, продолжайте читать эту статью для возможных шагов по устранению рисков.
Определение версии среды выполнения Jackson
В Azure Core 1.21.0 мы добавили возможности по определению среды выполнения и улучшенной диагностике версии среды выполнения Jackson.
Если отображается ошибка LinkageError
(или один из ее подклассов), связанная с API Jackson, просмотрите сообщение исключения и изучите сведения о версии среды выполнения. Например: 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 для Java. Пример: [main] ERROR com.azure.core.implementation.jackson.JacksonVersion - Version '2.9.0' of package 'jackson-core' is not supported (too old), please upgrade.
Примечание.
Убедитесь, что все пакеты Джексона имеют одну и ту же версию.
Список пакетов, используемых пакетом SDK Azure и поддерживаемыми версиями Джексона, см. в разделе "Поддержка нескольких версий Джексона ".
Устранение проблем с несовпадением версий
В следующих разделах описано, как устранить проблемы с несовпадением версий.
Использование спецификации пакета Azure SDK
Используйте последнюю стабильную спецификацию пакета Azure SDK и не указывайте версии пакета Azure SDK и зависимостей в файле POM. Если применимо, используйте спецификацию Azure Spring Boot.
Зависимости, указанные в спецификации пакета Azure SDK, тщательно протестированы на отсутствие конфликтов зависимостей.
Отказ от ненужных зависимостей
Если это можно сделать, удалите зависимости. Иногда приложение имеет зависимости от нескольких библиотек, предоставляющих практически одинаковые функции. Такие ненужные зависимости могут стать причиной уязвимостей, конфликтов версий в приложении, а также увеличить затраты на поддержку и обслуживание.
Обновление версий зависимостей
Если переключиться на последнюю версию BOM пакета SDK Azure не помогает, определите библиотеки, вызывающие конфликты, и компоненты, которые используют их. (Дополнительные сведения см. в разделе Просмотрите раздел дерева зависимостей ранее в этой статье.) Попробуйте обновить до более новой версии, которая защищает от уязвимостей системы безопасности и часто приносит новые функции, улучшения производительности и исправления ошибок.
Не рекомендуется понижать версию пакета Azure SDK, так как это может привести к появлению в приложении известных уязвимостей и проблем.
Затенение библиотек
Иногда невозможно подобрать сочетание библиотек, которые будут работать вместе, поэтому приходится использовать затенение.
Примечание.
Заливка имеет существенные недостатки: он увеличивает размер пакета и количество классов в классе, делает навигацию кода и отладку жесткой, не перемещает код JNI, нарушает отражение и может нарушать лицензии на код среди прочего. Его следует применять только в том случае, если другие варианты невозможны.
Заливка позволяет включать зависимости в JAR во время сборки, а затем переименовывать пакеты и обновлять код приложения, чтобы использовать код в затенённом расположении. Конфликт с ромбовидной зависимостью больше не является проблемой, так как доступно две разных копии зависимости. Вы можете затенить библиотеку, которая имеет конфликтующую транзитивную зависимость или прямую зависимость приложения, как описано в следующем списке:
- Конфликт транзитивной зависимости: например, для сторонней библиотеки
A
требуется Джексон 2.9, который пакеты SDK Azure не поддерживаются, и обновлениеA
невозможно. Создайте модуль, включающийA
и затеняющий (перемещающий) Jackson 2.9 и (при необходимости) другие зависимостиA
. - Конфликт зависимостей приложения: приложение использует Джексон 2.9 напрямую. Хотя вы работаете над обновлением кода, вы можете оттенить и переместить Джексон 2.9 в новый модуль с перемещенными классами Джексона.
Примечание.
Создание "толстого" JAR с помощью перемещенных классов Jackson не разрешает конфликт версий в этих примерах — это только приводит к созданию одной затененной версии Jackson.
Создание "толстого" JAR
Такие среды, как Databricks или Apache Spark, используют пользовательское управление зависимостями и предоставляют общие библиотеки, например Jackson. Чтобы избежать конфликтов с предоставляемыми библиотеками, вы можете создать "толстый" JAR со всеми зависимостями. Дополнительные сведения см. на странице подключаемого модуля затенения Apache Maven. Во многих случаях перемещение классов Jackson (com.fasterxml.jackson
) устраняет проблему. Иногда такие среды также устанавливают собственную версию пакетов Azure SDK, поэтому вы можете решить переместить имена пространств com.azure
, чтобы избежать конфликтов версий.
Описание совместимых версий зависимостей
Сведения о зависимостях и их версиях см. в azure-core
azure-core в центральном репозитории Maven Central. В следующей таблице приведены некоторые общие рекомендации:
Dependency | Поддерживаемые версии |
---|---|
Jackson | 2.10.0 и более новые дополнительные версии совместимы. Дополнительные сведения см. в разделе "Поддержка нескольких версий Джексона ". |
SLF4J | 1.7.* |
netty-tcnative-boringssl-static | 2.0.* |
netty-common | 4.1.* |
reactor-core | 3.X.* — номера основной и дополнительной версий должны точно соответствовать версиям, от которых зависит ваша версия azure-core . Дополнительные сведения см. в политике Project Reactor, касающейся прекращения поддержки. |
Поддержка нескольких версий Джексона
Пакет SDK Azure для Java поддерживает работу с несколькими версиями Джексона. Самая низкая поддерживаемая версия — Джексон 2.10.0. Клиентские библиотеки Azure SDK для Java настраивают конфигурацию и использование Джексона в зависимости от версии, обнаруженной во время выполнения. Эта корректировка обеспечивает более высокую совместимость со старыми версиями платформы Spring, Apache Spark и другими общими средами. Приложения могут уменьшать версии Джексона (до версии 2.10.0 или более поздней версии), не нарушая клиентские библиотеки Azure SDK для Java.
Примечание.
Использование старых версий Джексона может предоставлять приложениям известные уязвимости и проблемы. Дополнительные сведения см. в списке известных уязвимостей библиотек Джексона.
При закреплении определенной версии Джексона обязательно выполните это для всех модулей, используемых пакетом SDK Для Azure, которые показаны в следующем списке:
jackson-annotations
jackson-core
jackson-databind
jackson-dataformat-xml
jackson-datatype-jsr310
Миграция из Джексона в 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 для предотвращения проблем.