Разрешение зависимостей Maven (конфликтующее)
Допустим, у меня есть четыре проекта:
- Проект A (зависит от B и D)
- Проект B (зависит от D)
- Проект C (зависит от D)
- Проект D
В этом сценарии, если я запускаю проект A, Maven правильно разрешит зависимость от D. Если я правильно понимаю, Maven всегда берет зависимость с кратчайшим путем. Поскольку D является прямой зависимостью от A, она будет использоваться вместо D, который указан в B.
Но теперь предположим, что структура:
- Проект A (зависит от B и C)
- Проект B (зависит от D)
- Проект C (зависит от D)
- Проект D
В этом случае пути к разрешению D имеют одинаковую глубину. То, что происходит, - то, что у Maven будет конфликт. Я знаю, что можно сказать Мавену, что он должен исключить зависимости. Но мой вопрос, как решить такие проблемы. Я имею в виду, что в реальных приложениях у вас много зависимостей и, возможно, много конфликтов.
Является ли решение наилучшей практики действительно исключать вещи или есть другие возможные решения для этого? Мне очень трудно иметь дело с тем, когда я неожиданно получаю исключение ClassNotFound, потому что некоторые версии изменились, из-за чего Maven взял другую зависимость. Конечно, знание этого факта позволяет легко догадаться, что проблема в конфликте зависимостей.
Я использую Maven 2.1-SNAPSHOT.
Ответы
Ответ 1
Способ решения таких ситуаций, как это, заключается в том, чтобы включить раздел <dependencyManagement>
в корневой pom вашего проекта, где вы указываете, какая версия библиотеки будет использоваться.
EDIT:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>foo</groupId>
<artifactId>bar</artifactId>
<version>1.2.3</version>
</dependency>
</dependencies>
</dependencyManagement>
Теперь, независимо от того, какая версия библиотеки foo: bar запрашивается зависимостью, версия 1.2.3 всегда будет использоваться для этого проекта и всех подпроектов.
Справка:
Ответ 2
Maven может обрабатывать обе ситуации без каких-либо конфликтов. Конфликты будут существовать, когда требуются две версии транзитивной зависимости. ClassNotFoundException
вы описываете результаты приложения (или зависимости), пытающегося использовать класс, недоступный в версии конфликтуемой зависимости, которая фактически используется.
Существует несколько способов устранения проблемы.
- Обновите версии используемых вами библиотек, которые зависят от конфликтной зависимости, поэтому все они зависят от версии той же версии этой зависимости
- Объявить конфликтную зависимость как прямую зависимость вашего проекта с версией, которую вы хотите включить (в примере, с отсутствующим классом, включенным в нее)
- Укажите, какая версия конфликтной зависимости, которую должны использовать транзитивные зависимости, через раздел
<dependencyManagement>
POM
- Явно исключаю, чтобы нежелательные версии конфликтной зависимости включались в зависимости от зависимостей, которые полагаются на них, используя
<exclusion>
Ответ 3
Это принципиально не проблема maven, а проблема Java.
Если для проекта B и проекта C требуются две несовместимые версии проекта D, вы не можете использовать их как в проекте A.
Способ Maven разрешения таких конфликтов, к сожалению, как вы уже знаете, выбрать, какие из них исключить.
Использование mvn dependency:analyze
и mvn dependency:tree
помогает найти, какие конфликты у вас есть.
Ответ 4
Вы можете enforce согласованные зависимости во всем проекте с правилом Dependency Конвергенция.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-enforcer-plugin</artifactId>
<version>1.3.1</version>
<executions>
<execution>
<id>enforce</id>
<configuration>
<rules>
<DependencyConvergence/>
</rules>
</configuration>
<goals>
<goal>enforce</goal>
</goals>
</execution>
</executions>
</plugin>
Ответ 5
Одна из возможных стратегий - указать для основного проекта, какую версию D использовать (новейшую, например,). Однако, если библиотека D не поддерживает обратную совместимость, у вас есть проблема, о которой говорит kukudas - невозможно использовать обе библиотеки в вашем проекте.
В такой ситуации может потребоваться использование B или C в более старой версии, так что оба будут зависеть от совместимых версий D.