Различия между зависимости и управлением в Maven

768

В чем разница между 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 в родительском поме? Почему бы не определить его непосредственно в нужном модуле?

hguser
источник

Ответы:

465

Управление зависимостями позволяет консолидировать и централизовать управление версиями зависимостей без добавления зависимостей, которые наследуются всеми дочерними элементами. Это особенно полезно, когда у вас есть набор проектов (т.е. более одного), который наследует общего родителя.

Другим чрезвычайно важным случаем использования dependencyManagementявляется контроль версий артефактов, используемых в переходных зависимостях. Это трудно объяснить без примера. К счастью, это показано в документации.

Паскаль Тивент
источник
17
Итак, нужно ли в любом случае объявлять зависимости в pom дочернего проекта, даже если они объявлены в pom родительского проекта в разделе <dependencyManagement>? Можно ли сделать какое-то наследование зависимостей?
Джонни Би Гуд
56
Да, вам все еще нужно определить их в дочернем POM, чтобы показать, что вы их используете. Они на самом деле не включены в дочерние проекты только потому, что находятся в <dependencyManagement>родительском POM. Заключение зависимостей в <dependencyManagement>централизованное управление версией, областью действия и исключениями для каждой зависимости, если и когда вы решите ее использовать. Руководство Maven по управлению зависимостями раскрывает все детали.
hotshot309
2
Второй абзац ( dependencyManagementтакже управляет переходными зависимостями) верен только в том случае, если зависимости установлены явно: stackoverflow.com/questions/28312975/…
Роберт Метцгер,
2
@ johnny-b-goode Все, что вы можете сделать, - это создать новый dependenciesраздел в вашей родительской помпе. Мы сделали это так, чтобы все дочерние проекты имели по умолчанию некоторые apache-commons и не объявляли их постоянно.
рüффп
771

Я немного опаздываю на этот вопрос, но думаю, что он заслуживает более четкого ответа, чем принятый (который является правильным, но не подчеркивает фактическую важную часть, которую вы должны определить самостоятельно).

В родительском ПОМ основное различие между <dependencies> и <dependencyManagement>заключается в следующем:

Артефакты, указанные в <dependencies>разделе, ВСЕГДА будут включены как зависимость дочернего модуля (модулей).

Артефакты, указанные в <dependencyManagement>разделе, будут включены в дочерний модуль только в том случае, если они также были указаны в <dependencies>разделе самого дочернего модуля. Почему это хорошо, спросите вы? потому что вы указываете версию и / или область действия в родительском элементе, и вы можете не указывать их при указании зависимостей в дочернем POM. Это может помочь вам использовать унифицированные версии для зависимостей для дочерних модулей без указания версии в каждом дочернем модуле.

dcoder
источник
1
Но разве это не немного накладные расходы, использование <dependencyManagement>over <dependencies>в корне .pom? Ребенок pomможет быть намного короче.
Янез Кухар
18
Это правда. Использование <dependencies> вместо <dependencyManagement> создаст более короткие дочерние помпы. Тем не менее, это связано с затратами - это означает, что эти зависимости ВСЕГДА будут определены для ВСЕХ дочерних модулей. Если только некоторым из дочерних модулей требуется определенная зависимость, то использование «<dependencyManagement>» вместо этого позволит вам выбрать, какие дочерние модули будут иметь эту зависимость, и все же будет немного эффективнее, устанавливая версию зависимости только в родительском pom.
dcoder
2
@JanezKuhar Для меня имеет смысл, что если вы укажете зависимость в дочернем модуле, она переопределит зависимость в родительском модуле, но я признаю, что не помню. Я должен проверить документы Maven для этого, когда у меня будет шанс. Хотя может быть проще просто установить простой родительско-дочерний проект и проверить :)
dcoder
26
Хорошее объяснение простой концепции - почему Maven, по-видимому, так трудно объяснить свой собственный инструмент так легко?
jimmy_terra
1
Я бы добавил, Artifacts specified in the <dependencies> section will ALWAYS be included as a dependency of the child module(s)что они также включены в родительский. Кажется, невозможно установить зависимость для детей, но не для родителей.
кадуцей
54

документация на сайте Maven ужасна. То, что делает dependencyManagement, - это просто перемещает ваши определения зависимостей (версия, исключения и т. Д.) В родительский pom, а затем в дочерних poms вы просто должны поместить groupId и artifactId. Вот и все (кроме цепочки родительского pom и тому подобного, но это тоже не сложно) - dependencyManagement побеждает над зависимостями на родительском уровне - но если есть вопрос об этом или об импорте, документация Maven немного лучше).

Прочитав весь мусор 'a', 'b', 'c' на сайте Maven и запутавшись, я переписал их пример. Таким образом, если у вас есть 2 проекта (proj1 и proj2), которые имеют общую зависимость (betaShared), вы можете переместить эту зависимость до родительского pom. Пока вы занимаетесь этим, вы также можете перемещать любые другие зависимости (альфа и чарли), но только если это имеет смысл для вашего проекта. Таким образом, для ситуации, описанной в предыдущих предложениях, вот решение с зависимостью в родительском 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>
MattC
источник
2
Несколько не по теме вопрос: что означает тип зависимости "bar"? Я видел в примере pom на документации Maven, но не смог найти определение. Я предположил, что это опечатка «война» или «баночка», но я вижу это в других примерах, таких как ваш.
НиктоМан
NobodyMan - так что это просто заполнитель для другого типа архива. Например, использовать 'foo'. Или это может быть использовано, если кто-то сделал пользовательский тип с расширением 'bar'. И есть много неизвестных типов архивов. Например, sar, который является архивом сервиса jboss.
MattC
Ваш пример вполне понятен и подтверждает то, что я сам извлек из документации. Вы отправили его в проект Maven? Изучив ваш пример, я готовлюсь к упрощению POM, который имеет и требует только декларации зависимостей, поскольку у проекта, с которым он связан, нет дочерних элементов.
Дэвид А. Грей,
Я собирался отбросить узел DependencyManagement, пока мне не пришло в голову, что оставив его, я могу установить минимальную версию для любых дочерних POM, которые косвенно попадают в дерево зависимостей. Например, в погоне за javax.cache.cache-apI я обнаружил значительно более новую версию 1.0.0 (по сравнению с 0.3.0), которая также может использоваться повсеместно.
Дэвид А. Грей
Это объяснение прекрасно.
Smart Coder
45

Это как ты сказал; dependencyManagementиспользуется для извлечения всей информации о зависимостях в общий файл POM, упрощая ссылки в дочернем файле POM.

Это становится полезным, когда у вас есть несколько атрибутов, которые вы не хотите перепечатывать в нескольких дочерних проектах.

Наконец, dependencyManagementможет использоваться для определения стандартной версии артефакта для использования в нескольких проектах.

Пран
источник
4
Значит, зависимости не наследуются? В любом случае, его нужно объявить в поме детского проекта?
Джонни Би Гуд
6
Да, вам все равно нужно объявить их в дочерних проектах, но без указания версии.
Павел Власов
Этот сценарий полезен, когда вы хотите управлять версиями в нескольких проектах Java, имеющих отношения родитель-потомок.
Анудж Кумар
43

На мой взгляд, есть еще одна вещь, которая недостаточно освещена, и это нежелательное наследование .

Вот дополнительный пример:

Я заявляю в моем 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, и, следовательно, ваш модуль остается худым.

Андрейс
источник
Будут ли загружены зависимости, упомянутые в <dependencyManagement>, для родительского проекта pom?
Jaspreet Jolly
Вы уверены, что если мы используем <dependencyManagement>родительский pom, то по умолчанию зависимости не будут наследоваться в дочерних pom? Потому что в doc: maven.apache.org/guides/introduction/… при объяснении второго использования, <dependencyManagement>похоже, что он будет унаследован по умолчанию. В одной строке они говорят, что: «Когда maven запускается в проекте B, версия 1.0 артефактов a, b, c и d будет использоваться независимо от версии, указанной в их pom», даже если «b» не используется в проект Б
Чираг Сони
Попробуйте сами
Андрейс
17

Есть несколько ответов с указанием различий между <depedencies>и <dependencyManagement>тегами с Maven.

Тем не менее, несколько пунктов разработаны ниже в сжатой форме:

  1. <dependencyManagement>позволяет консолидировать все зависимости (используемые на уровне дочернего pom), используемые в разных модулях - ясность , централизованное управление версиями зависимостей
  2. <dependencyManagement>позволяет легко обновлять / понижать зависимости в зависимости от потребностей, в другом случае это необходимо выполнять на каждом дочернем уровне - согласованность
  3. зависимости, представленные в <dependencies>теге, всегда импортируются, в то время как зависимости, указанные <dependencyManagement>в родительском pom, будут импортированы, только если дочерний элемент pom имеет соответствующую запись в своем <dependencies>теге.
Амит Канерия
источник
17

Извините, я очень поздно на вечеринку.

Позвольте мне попытаться объяснить разницу с помощью mvn dependency:treeкоманды

Рассмотрим пример ниже

Parent 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>

Детский POM - модуль данных

<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 Commons указан как зависимость только в модуле данных (даже в родительском модуле)

IamVickyAV
источник
11

Если зависимость была определена в элементе зависимостей pom верхнего уровня, дочернему проекту не нужно было явно указывать версию зависимости. если дочерний проект действительно определил версию, он переопределит версию, указанную в разделе PivdencyManagement верхнего уровня. Таким образом, версия зависимостей используется только тогда, когда дочерний элемент не объявляет версию напрямую.

Мустафа Гювен
источник
1
Я считаю, что это утверждение может быть неверным. В примерах управления зависимостями Maven (# 2) говорится, что зависимости, определенные в родительском pom с версией, переопределяют версию, указанную в дочернем pom: «Когда maven запускается в проекте B версии 1.0 с артефактами a, b, c , и d будет использоваться независимо от версии, указанной в их pom. "
devdanke
@devdanke По крайней мере, Eclipse m2e выдает предупреждение: Переопределение удалось версии ... для ... .
GeroldBroser восстанавливает Монику
4

В родительском POM основное различие между <dependencies>и <dependencyManagement>заключается в следующем:

Артефакты, указанные в <dependencies>разделе, ВСЕГДА будут включены как зависимость дочернего модуля (модулей).

Артефакты, указанные в разделе, будут включены в дочерний модуль только в том случае, если они также были указаны в разделе самого дочернего модуля. Почему это хорошо, спросите вы? потому что вы указываете версию и / или область действия в родительском элементе, и вы можете не указывать их при указании зависимостей в дочернем POM. Это может помочь вам использовать унифицированные версии для зависимостей для дочерних модулей без указания версии в каждом дочернем модуле.

Yaver
источник
4

Просто, по моим собственным словам, вы parent-projectпоможете вам обеспечить 2 вида зависимостей:

  • неявные зависимости : все зависимости, определенные <dependencies>в вашем разделе parent-project, наследуются всемиchild-projects
  • явные зависимости : позволяет выбрать зависимости для применения в вашем child-projects. Таким образом, вы используете <dependencyManagement>раздел, чтобы объявить все зависимости, которые вы собираетесь использовать в вашем другом child-projects. Самое главное, что в этом разделе вы определяете, <version>чтобы вам не приходилось объявлять его снова в своем child-project.

С <dependencyManagement>моей точки зрения (поправьте меня, если я ошибаюсь) просто полезно, помогая вам централизовать версию ваших зависимостей. Это что-то вроде вспомогательной функции.

Гарри Кодер
источник
1

В Eclipse есть еще одна особенность dependencyManagement. Когда dependenciesиспользуется без него, необнаруженные зависимости замечены в файле pom. Если dependencyManagementиспользуется, неразрешенные зависимости остаются незамеченными в pom-файле, а ошибки появляются только в java-файлах. (импорт и прочее ...)

Гангнус
источник
1

Разница между ними лучше всего заключается в том, что кажется необходимым и достаточным определением элемента 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, а классификатор по умолчанию равен нулю ». [ https://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html ]

Таким образом, все подэлементы (область действия, исключения и т. Д.) Элемента зависимости - кроме groupId, artifactId, типа, классификатора, а не только версии - доступны для блокировки / дефолта в точке (и, таким образом, наследуются от там далее) вы указываете зависимость внутри dependencyElement. Если бы вы указали зависимость с подэлементами type и classifier (см. Первую цитируемую веб-страницу, чтобы проверить все подэлементы) как не jar и не null соответственно, вам потребуется {groupId, artifactId, classifier, type} ссылаться (разрешать) эту зависимость в любой точке наследования, происходящего из элемента dependencyManagement. Иначе, {groupId, artifactId} будет достаточно, если вы не собираетесь переопределять значения по умолчанию для классификатора и типа (jar и null соответственно). Так что по умолчанию это хорошее ключевое слово в этом определении; любой подэлемент (ы) (кроме groupId,

Таким образом, любой элемент зависимостей за пределами dependencyManagement, будь то ссылка на какой-либо элемент dependencyManagement или автономный, немедленно разрешается (т.е. устанавливается в локальный репозиторий и доступен для путей к классам).

число оборотов в секунду
источник