Различия между зависимости и управлением в Maven
В чем разница между dependencyManagement
а также dependencies
? Я видел документы на веб-сайте Apache Maven. Кажется, что зависимость, определенная под dependencyManagement
может использоваться в своих дочерних модулях без указания версии.
Например:
Родительский проект (Pro-par) определяет зависимость под dependencyManagement
:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8</version>
</dependency>
</dependencies>
</dependencyManagement>
Тогда в потомке Pro-par я могу использовать junit:
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
</dependencies>
Однако мне интересно, нужно ли определять junit в родительском pom? Почему бы не определить его непосредственно в нужном модуле?
16 ответов
Dependency Management позволяет консолидировать и централизовать управление версиями зависимостей без добавления зависимостей, которые наследуются всеми дочерними элементами. Это особенно полезно, когда у вас есть набор проектов (то есть более одного), который наследует общего родителя.
Еще один чрезвычайно важный случай использования dependencyManagement
это контроль версий артефактов, используемых в переходных зависимостях. Это трудно объяснить без примера. К счастью, это показано в документации.
Я немного опаздываю на этот вопрос, но думаю, что он заслуживает более четкого ответа, чем принятый (который является правильным, но не подчеркивает фактическую важную часть, которую вы должны определить самостоятельно).
В родительском ПОМ основное различие между <dependencies>
а также <dependencyManagement>
это:
Артефакты, указанные в <dependencies>
section ВСЕГДА будет включен как зависимость дочернего модуля (модулей).
Артефакты, указанные в <dependencyManagement>
раздел, будет включен в дочерний модуль, только если они были указаны в <dependencies>
раздел самого дочернего модуля. Почему это хорошо, спросите вы? потому что вы указываете версию и / или область действия в родительском элементе, и вы можете не указывать их при указании зависимостей в дочернем POM. Это может помочь вам использовать унифицированные версии для зависимостей для дочерних модулей без указания версии в каждом дочернем модуле.
На мой взгляд, есть еще одна вещь, которая недостаточно освещена, и это нежелательное наследование.
Вот дополнительный пример:
Я заявляю в моем parent
П:
<dependencies>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>19.0</version>
</dependency>
</dependencies>
бум! У меня это в моем Child A
, Child B
а также Child C
модули:
- Причастность, унаследованная от детских помпонов
- Единственное место для управления
- Не нужно что-либо переопределять в детских помпонах
- Я все еще могу redelcare и переопределить
version 18.0
вChild B
если я захочу.
Но что, если мне не понадобится гуава в Child C
и ни в будущем Child D
а также Child E
модули?
Они все еще унаследуют это, и это нежелательно! Это так же, как запах кода Java God Object, где вы наследуете некоторые полезные биты от класса, а также массу нежелательных вещей.
Это где <dependencyManagement>
вступает в игру. Когда вы добавляете это в родительский pom, все ваши дочерние модули перестают его видеть. И, таким образом, вы вынуждены заходить в каждый отдельный модуль, который ему нужен, и объявлять его снова (Child A
а также Child B
без версии, хотя).
И, очевидно, вы не делаете это для Child C
и, таким образом, ваш модуль остается худым.
Документация на сайте Maven ужасна. То, что делает dependencyManagement, - это просто перемещает ваши определения зависимостей (версия, исключения и т. Д.) В родительский pom, а затем в дочерние poms вы просто должны поместить groupId и artifactId. Вот и все (за исключением цепочки родительского pom и тому подобного, но это тоже не сложно) - dependencyManagement побеждает над зависимостями на родительском уровне - но если есть вопрос об этом или об импорте, документация Maven будет немного лучше).
Прочитав весь мусор 'a', 'b', 'c' на сайте Maven и запутавшись, я переписал их пример. Таким образом, если у вас есть 2 проекта (proj1 и proj2), которые имеют общую зависимость (betaShared), вы можете переместить эту зависимость до родительского pom. Пока вы занимаетесь этим, вы также можете перемещать любые другие зависимости (альфа и Чарли), но только если это имеет смысл для вашего проекта. Таким образом, для ситуации, изложенной в предыдущих предложениях, вот решение с зависимостью Management в родительском pom:
<!-- ParentProj pom -->
<project>
<dependencyManagement>
<dependencies>
<dependency> <!-- not much benefit defining alpha here, as we only use in 1 child, so optional -->
<groupId>alpha</groupId>
<artifactId>alpha</artifactId>
<version>1.0</version>
<exclusions>
<exclusion>
<groupId>zebra</groupId>
<artifactId>zebra</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>charlie</groupId> <!-- not much benefit defining charlie here, so optional -->
<artifactId>charlie</artifactId>
<version>1.0</version>
<type>war</type>
<scope>runtime</scope>
</dependency>
<dependency> <!-- defining betaShared here makes a lot of sense -->
<groupId>betaShared</groupId>
<artifactId>betaShared</artifactId>
<version>1.0</version>
<type>bar</type>
<scope>runtime</scope>
</dependency>
</dependencies>
</dependencyManagement>
</project>
<!-- Child Proj1 pom -->
<project>
<dependencies>
<dependency>
<groupId>alpha</groupId>
<artifactId>alpha</artifactId> <!-- jar type IS DEFAULT, so no need to specify in child projects -->
</dependency>
<dependency>
<groupId>betaShared</groupId>
<artifactId>betaShared</artifactId>
<type>bar</type> <!-- This is not a jar dependency, so we must specify type. -->
</dependency>
</dependencies>
</project>
<!-- Child Proj2 -->
<project>
<dependencies>
<dependency>
<groupId>charlie</groupId>
<artifactId>charlie</artifactId>
<type>war</type> <!-- This is not a jar dependency, so we must specify type. -->
</dependency>
<dependency>
<groupId>betaShared</groupId>
<artifactId>betaShared</artifactId>
<type>bar</type> <!-- This is not a jar dependency, so we must specify type. -->
</dependency>
</dependencies>
</project>
Это как ты сказал; dependencyManagement
используется для извлечения всей информации о зависимостях в общий файл POM, упрощая ссылки в дочернем файле POM.
Это становится полезным, когда у вас есть несколько атрибутов, которые вы не хотите перепечатывать в нескольких дочерних проектах.
В заключение, dependencyManagement
может использоваться для определения стандартной версии артефакта для использования в нескольких проектах.
Извините, я очень опоздал на вечеринку.
Позвольте мне попытаться объяснить разницу, используя mvn dependency:tree
команда
Рассмотрим пример ниже
Родительский POM - Мой проект
<modules>
<module>app</module>
<module>data</module>
</modules>
<dependencies>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>19.0</version>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.9</version>
</dependency>
</dependencies>
</dependencyManagement>
Дочерний ПОМ - модуль данных
<dependencies>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
</dependencies>
Дочерний POM - модуль приложения (не имеет дополнительных зависимостей, поэтому оставьте зависимости пустыми)
<dependencies>
</dependencies>
На бегу mvn dependency:tree
команда, получаем следующий результат
Scanning for projects...
------------------------------------------------------------------------
Reactor Build Order:
MyProject
app
data
------------------------------------------------------------------------
Building MyProject 1.0-SNAPSHOT
------------------------------------------------------------------------
--- maven-dependency-plugin:2.8:tree (default-cli) @ MyProject ---
com.iamvickyav:MyProject:pom:1.0-SNAPSHOT
\- com.google.guava:guava:jar:19.0:compile
------------------------------------------------------------------------
Building app 1.0-SNAPSHOT
------------------------------------------------------------------------
--- maven-dependency-plugin:2.8:tree (default-cli) @ app ---
com.iamvickyav:app:jar:1.0-SNAPSHOT
\- com.google.guava:guava:jar:19.0:compile
------------------------------------------------------------------------
Building data 1.0-SNAPSHOT
------------------------------------------------------------------------
--- maven-dependency-plugin:2.8:tree (default-cli) @ data ---
com.iamvickyav:data:jar:1.0-SNAPSHOT
+- org.apache.commons:commons-lang3:jar:3.9:compile
\- com.google.guava:guava:jar:19.0:compile
Google guava указана как зависимость в каждом модуле (включая родительский), тогда как общие ресурсы apache указаны как зависимость только в модуле данных (даже не в родительском модуле)
Есть несколько ответов о различиях между <depedencies>
а также <dependencyManagement>
Теги с Maven.
Тем не менее, несколько пунктов разработаны ниже в сжатой форме:
<dependencyManagement>
позволяет консолидировать все зависимости (используемые на уровне дочернего pom), используемые в разных модулях - ясность, централизованное управление версиями зависимостей<dependencyManagement>
позволяет легко обновлять / понижать зависимости в зависимости от потребностей, в другом случае это необходимо выполнять на каждом дочернем уровне - согласованность- зависимости, представленные в
<dependencies>
тег всегда импортируется, а зависимости предоставляются в<dependencyManagement>
в родительском пом будет импортироваться, только если дочерний пом имеет соответствующую запись в своем<dependencies>
тег.
Если зависимость была определена в элементе зависимостей pom верхнего уровня, дочернему проекту не нужно было явно указывать версию зависимости. если дочерний проект действительно определил версию, он переопределит версию, указанную в разделе PivdencyManagement верхнего уровня. Таким образом, версия dependencyManagement используется только тогда, когда дочерний элемент не объявляет версию напрямую.
Просто своими словами, твой parent-project
помогает предоставить 2 вида зависимостей:
- неявные зависимости: все зависимости, определенные в
<dependencies>
раздел в вашемparent-project
наследуются всемиchild-projects
- явные зависимости: позволяет выбрать зависимости для применения в вашем
child-projects
. Таким образом, вы используете<dependencyManagement>
раздел, чтобы объявить все зависимости, которые вы собираетесь использовать в разныхchild-projects
. Самое главное, что в этом разделе вы определяете<version>
так что вам не придется снова объявлять это в своемchild-project
.
В <dependencyManagement>
с моей точки зрения (поправьте меня, если я ошибаюсь) просто полезен, помогая вам централизовать версию ваших зависимостей. Это своего рода вспомогательная функция.
В родительском ПОМ основное различие между <dependencies>
а также <dependencyManagement>
это:
Артефакты, указанные в <dependencies>
section ВСЕГДА будет включен как зависимость дочернего модуля (модулей).
Артефакты, указанные в разделе, будут включены в дочерний модуль только в том случае, если они также были указаны в разделе самого дочернего модуля. Почему это хорошо, спросите вы? потому что вы указываете версию и / или область действия в родительском элементе, и вы можете не указывать их при указании зависимостей в дочернем POM. Это может помочь вам использовать унифицированные версии для зависимостей для дочерних модулей без указания версии в каждом дочернем модуле.
Один из вариантов использования - разрешение конфликта версий библиотеки.
Пример:
- У проекта A есть библиотека x:1.0.1
- У проекта A есть библиотека B
- Библиотека B имеет библиотеку x:1.0.0
Имея этот набор, вы получите конфликт, имея проект A как
x:1.0.1
и
x:1.0.0
. Чтобы решить эту проблему, вы можете поместить зависимость от конкретной версии в
<dependencyManagement>
ярлык
Разница между ними лучше всего проявляется в том, что кажется необходимым и достаточным определением элемента dependencyManagement, доступного в документации веб-сайта Maven:
dependencyManagement
"Информация о зависимостях по умолчанию для проектов, которые наследуются от этого. Зависимости в этом разделе не разрешаются немедленно. Вместо этого, когда POM, производный от этого, объявляет зависимость, описываемую соответствующими groupId и artifactId, версией и другими значениями из этого раздела используются для этой зависимости, если они еще не были указаны ".[ https://maven.apache.org/ref/3.6.1/maven-model/maven.html ]
Его следует читать вместе с дополнительной информацией, доступной на другой странице:
"… минимальный набор информации для сопоставления ссылки зависимости с разделом dependencyManagement - это на самом деле {groupId, artifactId, type, classifier}. Во многих случаях эти зависимости будут относиться к артефактам jar без классификатора. Это позволяет нам сокращать идентификатор, установленный на {groupId, artifactId}, поскольку значение по умолчанию для поля типа - jar, а классификатор по умолчанию - null ". [ https://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html ]
Таким образом, все подэлементы (область действия, исключения и т. Д.) Элемента зависимости - кроме groupId, artifactId, типа, классификатора, а не только версии - доступны для блокировки / по умолчанию в точке (и, таким образом, унаследованы от там и далее) вы указываете зависимость внутри dependencyElement. Если вы указали зависимость с подэлементами типа и классификатора (см. Первую процитированную веб-страницу, чтобы проверить все подэлементы) как not jar и not null соответственно, вам потребуются {groupId, artifactId, classifier, type} для ссылки (разрешения) этой зависимости в любой точке наследования, происходящего от элемента dependencyManagement. Иначе, {groupId, artifactId} будет достаточно, если вы не собираетесь переопределять значения по умолчанию для классификатора и типа (jar и null соответственно). Таким образом, default - хорошее ключевое слово в этом определении;любые подэлементы (кроме groupId, artifactId, классификатора и типа, конечно) явно присвоенные значения в точке, где вы ссылаетесь на зависимость, переопределяют значения по умолчанию в элементе dependencyManagement.
Таким образом, любой элемент зависимости вне dependencyManagement, будь то ссылка на какой-либо элемент dependencyManagement или как автономный, немедленно разрешается (то есть устанавливается в локальный репозиторий и доступен для путей к классам).
Не рекомендую использовать.
Единственное преимущество его использования заключается в том, что вы можете определить версию в родительском pom и вам не нужно снова определять ее в дочернем pom. Но если у вас есть набор проектов (особенно микросервисных проектов). С использованием
dependencyManagement
не имеет никаких преимуществ.
Разным проектам могут потребоваться разные зависимости. Зачем унаследовать его от того же родительского pom. Сделайте это как можно проще . Если одному проекту нужна зависимость, добавьте ее в файл pom. Не путайте разработчиков.
В Eclipse есть еще одна особенность dependencyManagement
, когда dependencies
используется без него, необнаруженные зависимости замечены в файле pom. Если dependencyManagement
используется, неразрешенные зависимости остаются незамеченными в pom-файле, а ошибки появляются только в java-файлах. (импорт и прочее...)
Это было объяснено здесь , чтобы было легко понять. Заключительная разница между dependencyManagement и зависимостями заключается в объявлении и фактическом добавлении
Если у вас все равно есть родительский помпон, то, на мой взгляд, использование <dependencyManagement>
просто управление версией (и, возможно, областью действия) - пустая трата места и сбивает с толку младших разработчиков.
В любом случае у вас, вероятно, будут свойства для версий в каком-то файле parent-pom. Почему бы просто не использовать эти свойства в дочерних помпах? Таким образом, вы по-прежнему можете обновлять версию в свойстве (в пределах parent-pom) для всех дочерних проектов сразу. Это имеет тот же эффект, что и<dependencyManagement>
просто без <dependencyManagement>
.
По моему мнению, <dependencyManagement>
следует использовать для "реального" управления зависимостями, такими как исключения и т.п.