Различия между зависимости и управлением в 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.

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

  1. <dependencyManagement> позволяет консолидировать все зависимости (используемые на уровне дочернего pom), используемые в разных модулях - ясность, централизованное управление версиями зависимостей
  2. <dependencyManagement> позволяет легко обновлять / понижать зависимости в зависимости от потребностей, в другом случае это необходимо выполнять на каждом дочернем уровне - согласованность
  3. зависимости, представленные в <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> следует использовать для "реального" управления зависимостями, такими как исключения и т.п.

Другие вопросы по тегам