Решение проблем конвергенции зависимостей Maven
Я использую плагин maven-forcer для проверки проблем сходимости зависимостей. Типичный результат будет:
[WARNING] Rule 1: org.apache.maven.plugins.enforcer.DependencyConvergence failed
with message:
Failed while enforcing releasability the error(s) are [
Dependency convergence error for junit:junit:3.8.1 paths to dependency are:
+-foo:bar:1.0-SNAPSHOT
+-ca.juliusdavies:not-yet-commons-ssl:0.3.9
+-commons-httpclient:commons-httpclient:3.0
+-junit:junit:3.8.1
and
+-foo:bar:1.0-SNAPSHOT
+-junit:junit:4.11
]
Видя это сообщение, я обычно "решаю" его, исключая транзитивную зависимость, например
<dependency>
<groupId>ca.juliusdavies</groupId>
<artifactId>not-yet-commons-ssl</artifactId>
<version>0.3.9</version>
<exclusions>
<!-- This artifact links to another artifact which stupidly includes
junit in compile scope -->
<exclusion>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</exclusion>
</exclusions>
</dependency>
Я хотел бы понять, действительно ли это исправление и риски, связанные с исключением библиотек таким образом. Как я вижу это:
Исправление обычно безопасно при условии, что я выбрал более новую версию. Это зависит от авторов библиотеки, поддерживающих обратную совместимость.
Как правило, это не влияет на сборку Maven (поскольку побеждает более близкое определение), однако, исключая зависимость, я говорю Maven, что знаю об этой проблеме, и, таким образом, успокаиваю плагин maven-inspecer-plugin.
Правильны ли мои мысли и есть ли альтернативный способ решения этой проблемы? Я заинтересован в ответах, которые сосредоточены на общем случае - я понимаю, junit
Пример выше немного странный.
3 ответа
Мы все согласны с тем, что JUnit никогда не следует устанавливать в другую область, чем test
, Вообще говоря, я тоже не думаю, что есть иное решение, кроме исключения нежелательной зависимости, поэтому мы все согласны с тем, что вы правы в этом.
ПРОСТОЙ СЛУЧАЙ:
Как говорит Андреас Крюгер, с версиями может быть риск (я действительно сталкивался с ним). Допустим, что зависимости проекта следующие:
+-foo:bar:1.0-SNAPSHOT
+-group1:projectA:2.0
+-group2:projectB:3.8.1
+-group2:projectB:4.11
Обратите внимание, что это всего лишь упрощение вашего случая. Видя это дерево зависимостей, вы бы исключили зависимость projectB, заданную projectA:
<dependency>
<groupId>group1</groupId>
<artifactId>projectA</artifactId>
<version>2.0</version>
<exclusions>
<exclusion>
<groupId>group2</groupId>
<artifactId>projectB</artifactId>
</exclusion>
</exclusions>
</dependency>
После упаковки проекта с помощью maven оставшейся зависимостью будет group2-someProjectB-4.11.jar, версия 4.11, а не 3.8.1. Все будет хорошо, и проект будет работать без каких-либо проблем.
Затем, через некоторое время, допустим, вы решили перейти на следующую версию проекта A, версию 3.0, которая добавляет новые замечательные функции:
<dependency>
<groupId>group1</groupId>
<artifactId>projectA</artifactId>
<version>3.0</version>
<exclusions>
<exclusion>
<groupId>group2</groupId>
<artifactId>projectB</artifactId>
</exclusion>
</exclusions>
</dependency>
Проблема в том, что вы еще не знаете, что projectA версии 3.0 также обновило свою зависимость projectB до версии 5.0:
+-foo:bar:1.0-SNAPSHOT
+-group1:projectA:3.0
+-group2:projectB:5.0
+-group2:projectB:4.11
В этом случае исключение, которое вы сделали бы некоторое время назад, исключает ProjectB версии 5.0.
Однако ProjectA версии 3.0 требует улучшений по сравнению с проектом B версии 5.0. Из-за исключения после упаковки проекта с помощью maven оставшейся зависимостью будет group2-someProjectB-4.11.jar, версия 4.11, а не 5.0. В настоящее время вы используете любую из новых функций ProjectA, программа не будет работать правильно.
ЧТО ТАКОЕ РЕШЕНИЕ?
Я столкнулся с этой проблемой в проекте Java-EE.
Команда разработала базу данных сервисов. Они упаковали это как projectA. Каждый раз, когда они обновляли службы, они также обновляли файл, в котором перечислены все их текущие зависимости и текущие версии.
ProjectA был зависимостью для проекта Java-EE, над которым я работал. Каждый раз, когда сервисная команда обновляла ProjectA, я также проверял обновления версий.
На самом деле, нет никакого вреда в исключении зависимости. Но каждый раз, когда вы обновляете зависимость, где было установлено исключение, вы должны проверять:
- если это исключение все еще имеет смысл.
- если вам нужно обновить версию исключенной зависимости в вашем собственном проекте.
Я предполагаю, что исключения из мавена похожи на кухонные ножи. Он острый, нарезает овощи без усилий, но требует осторожности при обращении с ним...
Если JUnit как артефакт становится зависимостью в области компиляции, это ошибка одной из ваших библиотек, здесь: ca.juliusdavies.
JUnit всегда должен быть включен в область тестирования. Таким образом, при успешной сборке он не упаковывается в полученный файл.jar, .war или.ear.
Вообще говоря, нет никакого вреда в исключении уже включенных зависимостей, как, например, когда библиотека 1 и библиотека 2 имеют одну общую зависимость.
Конечно, единственная проблема, которая может возникнуть, заключается в том, что библиотека 1 и библиотека 2 содержат разные версии одного и того же зависимого артефакта. Это может привести к ошибкам во время выполнения, когда функции библиотеки изменились. К счастью, это не всегда так, если только разница в номерах версий не велика. Как правило, рекомендуется включать последнюю версию зависимости и исключать более старую. Это в большинстве случаев жизнеспособно.
Если нет, проверьте, есть ли обновления для зависимостей первого уровня вашего проекта.
Лучший способ решить эту проблему с зависимостями при использовании Enforcer в проекте. Следует добавить ошибку, вызывающую зависимость в управлении зависимостями, т.е. pom.xml, как в этом junit, вызывает проблему, поэтому выберите более высокую версию и добавьте как зависимость в pom.xml
<dependency><groupId>junit_or_group_id_error_causing_dependency</groupId><artifactId>Junit_or_artifact_id_group_id_error_causing_dependency</artifactId><version>4.11_or_higher_version_of_error_causing_dependency</version></dependency>
Исключение может быть другим решением, но я нашел более чистый способ сделать то же самое.