Відмінності між залежністю управління та залежностями в Мевена


766

У чому різниця між dependencyManagementі dependencies? Я бачив документи на веб-сайті Apache Maven. Здається, що залежність, визначена під dependencyManagementcan, може бути використана в її дочірніх модулях без зазначення версії.

Наприклад:

Батьківський проект (Pro-par) визначає залежність відповідно до dependencyManagement:

<dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8</version>
    </dependency>
 </dependencies>
</dependencyManagement>

Тоді у дитини Pro-par я можу користуватися джунітом:

  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
    </dependency>
 </dependencies>

Однак мені цікаво, чи потрібно визначити junit у батьківській пом? Чому б не визначити його безпосередньо в потрібному модулі?

Відповіді:


463

Управління залежністю дозволяє консолідувати та централізувати управління версіями залежностей без додавання залежностей, які успадковуються всіма дітьми. Це особливо корисно, коли у вас є набір проектів (тобто декілька), які успадковують спільного батька.

Іншим надзвичайно важливим випадком використання dependencyManagementє контроль версій артефактів, які використовуються в перехідних залежностях. Це важко пояснити без прикладу. На щастя, це проілюстровано в документації.


17
Отже, її потреба декларувати залежності у пам’яті дочірнього проекту все-таки, навіть якщо вони були заявлені в пам’яті батьківського проекту у розділі <dependencyManagement>? Чи можливо зробити якесь спадкування залежностей?
— johnny-b-goode

55
Так, вам все-таки потрібно визначити їх у дочірній ПОМ, щоб показати, що ви їх використовуєте. Вони насправді не включаються до дочірніх проектів лише тому, що вони знаходяться в <dependencyManagement>батьківській програмі POM. Включення залежностей у <dependencyManagement>централізоване управління версією, областю та виключеннями для кожної залежності, якщо і коли ви вирішите її використовувати. Посібник Мейвена щодо управління залежністю описується у всіх деталях.
— hotshot309

2
Другий абзац ( dependencyManagementтакож керує транзитивними залежностями) істинним є лише тоді, коли явно встановлені залежності: stackoverflow.com/questions/28312975/…
— Роберт Мецгер

2
@ johnny-b-goode Що ви ще можете зробити, це створити новий dependenciesрозділ у батьківській пам’яті. Ми зробили це для того, щоб усі дочірні проекти за замовчуванням мали деякі apache-commons і не декларували їх весь час.
— рüффп

769

Я модно запізнююся на це питання, але я вважаю, що варто отримати чіткішу відповідь, ніж прийнята (що є правильним, але не підкреслює важливу частину, яку потрібно вивести самостійно).

У батьківській POM головна відмінність між і <dependencies>та <dependencyManagement>полягає в цьому:

Артефакти, зазначені в <dependencies>розділі, ВЖЕ завжди включатимуться як залежність дочірнього модуля.

Артефакти, зазначені в <dependencyManagement>розділі, будуть включені до дочірнього модуля лише у тому випадку, якщо вони також були вказані в <dependencies>розділі самого дочірнього модуля. Чому добре запитати? тому що ви вказуєте версію та / або сферу застосування у батьків, і ви можете їх вимкнути, вказуючи залежності в дочірній POM. Це може допомогти вам використовувати уніфіковані версії для залежностей для дочірніх модулів, не вказуючи версію в кожному дочірньому модулі.


1
Але не це також трохи накладні витрати, використовуючи <dependencyManagement>більш <dependencies>докорінно .pom? Дитина pomможе бути набагато коротше.
— Janez Kuhar

18
Це правда. Використання <dependitions> замість <dependencyManagement> створить коротші дочки. Однак, це пов'язано з вартістю - це означає, що ці ЗАВЖДИ визначатимуться для ВСІХ дочірніх модулів. Якщо тільки ДЕЯКІД дочірніх модулів потребують певної залежності, ніж використання "<dependencyManagement>" натомість дозволить вам вибрати, які дочірні модулі матимуть цю залежність, і все ж бути трохи ефективнішим, встановивши версію залежності лише у батьківській пам’яті.
— dcoder

2
@JanezKuhar Для мене має сенс, що якщо ви вкажете залежність у дочірньому модулі, це перекриє ту, що є у батьків, але я визнаю, що не пам'ятаю. Мені доведеться перевірити документи Maven на те, коли я отримаю можливість. Хоча може бути простіше просто налаштувати простий проект батько-дитина і перевірити :)
— dcoder

26
Хороше пояснення простої концепції - чому Мевен, здається, так важко пояснити власний інструмент?
— jimmy_terra

1
Я додам, Artifacts specified in the <dependencies> section will ALWAYS be included as a dependency of the child module(s)що вони також включені до батьків. Вважається неможливим встановити залежність для дітей, але не для батьків.
— кадуцей

54

Документація на сайті Maven жахлива. Що таке Управління залежностей - це просто перемістити визначення залежностей (версія, виключення тощо) до батьківської пам’яті, тоді в дочірніх друзях потрібно просто поставити groupId і artifactId. Це все (за винятком батьківського ланцюга пам’яті тощо), але це теж не так вже й складно - залежністьManagement виграє залежність на батьківському рівні - але якщо у вас є питання щодо цього чи імпорту, документація Maven трохи краща).

Прочитавши все сміття 'a', 'b', 'c' на сайті Maven і розгубившись, я переписав їхній приклад. Отже, якщо у вас було 2 проекти (proj1 та proj2), які мають спільну залежність (betaShared), ви могли б перенести цю залежність до батьківської пом. Поки ви перебуваєте на цьому, ви також можете рухатись до будь-яких інших залежностей (альфа та чарлі), але лише якщо це має сенс для вашого проекту. Отже, для ситуації, викладеної в попередніх реченнях, ось рішення з залежністю управління в батьківській пом:

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

2
Дещо поза тематичне запитання: що означає тип залежності "бар"? Я бачив на прикладі пом на документацію 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
Отже, залежності не успадковується? Її необхідність все-таки задекларувати в пам’яті дитячого проекту?
— johnny-b-goode

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>вступає в гру. Коли ви додасте це до батьківського пам’яті, всі ваші дочірні модулі ЗАСТОСУЮТЬ його . І, таким чином, ви змушені зайти в кожен окремий модуль, якому він потрібен, і оголосити його знову ( Child Aі Child Bбез версії, хоча).

І, очевидно, ви цього не робите Child C, і, отже, ваш модуль залишається худорлявим.


Чи залежать зазначені в <dependencyManagement> залежності для батьківського проекту?
— Jaspreet Jolly

Ви впевнені, що якщо ми будемо використовувати <dependencyManagement>в батьківській пом, то за замовчуванням залежності не будуть успадковані в дитячих птах? Тому що в документі doc: maven.apache.org/guides/introduction/… під час пояснення другого використання <dependencyManagement>цього виглядає так, що він буде успадкований за замовчуванням. В одному рядку вони говорять, що: "Коли Maven запускається за проектом B, версія 1.0 артефактів a, b, c і d буде використовуватися незалежно від версії, зазначеної в їхній пом", хоча "b" не використовується в проект B
— chirag soni

Спробуйте самі
— Андрейс,

17

Є кілька відповідей, які окреслюють відмінності між <depedencies>та <dependencyManagement>тегами з Maven.

Однак декілька пунктів, детально викладених нижче, стисло:

  1. <dependencyManagement>дозволяє консолідувати всі залежності (використовуються на рівні дочірньої пом), що використовуються в різних модулях - чіткість , управління версіями центральної залежності
  2. <dependencyManagement>дозволяє легко модернізувати / зменшувати залежність залежно від потреби, в іншому випадку це потрібно здійснювати на кожному рівні пам’яті дитини - послідовність
  3. Залежності, що надаються в <dependencies>тегу, завжди імпортуються, тоді як залежності, надані <dependencyManagement>у батьківському пом, будуть імпортовані лише у тому випадку, якщо дочірній пом має відповідний запис у своєму <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>

Child 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 вказаний як залежність лише в модулі даних (навіть не в батьківському модулі)


11

Якщо залежність була визначена в елементі залежності залежності від найвищого рівня, дочірньому проекту не довелося чітко перераховувати версію залежності. якщо дочірній проект визначив версію, він би замінив версію, перелічену в розділі залежності POM вищого рівня. Тобто версія залежність управління використовується лише тоді, коли дитина не оголошує версію безпосередньо.


1
Я вважаю, що це твердження може бути невірним. У прикладах управління залежністю Maven (№2) вони говорять, що залежності, визначені в батьківському pom з версією, переведуть версію, вказану в дочірній пам’яті: "Коли Maven запускається за проектом B версії 1.0 артефактів a, b, c , і d буде використовуватися незалежно від версії, вказаної в їхній пам’яті. "
— девданке

@devdanke Принаймні, Eclipse m2e видає попередження: Перевизначення вдалося версії ... для ... .
— ГерольдБрозер повертає Моніку

4

У батьківській POM головна відмінність між і <dependencies>та <dependencyManagement>полягає в цьому:

Артефакти, зазначені в <dependencies>розділі, ВЖЕ завжди включатимуться як залежність дочірнього модуля.

Артефакти, зазначені в розділі, будуть включені до дочірнього модуля лише у тому випадку, якщо вони також були вказані в розділі самого дочірнього модуля. Чому добре запитати? тому що ви вказуєте версію та / або сферу застосування у батьків, і ви можете їх вимкнути, вказуючи залежності в дочірній POM. Це допоможе вам використовувати уніфіковані версії для залежностей для дочірніх модулів, не вказуючи версію в кожному дочірньому модулі.


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

Різниця між ними найкраще пояснюється тим, що здається необхідним і достатнім для визначення елемента залежностіУправління, доступного в документах веб-сайту Maven:

залежністьУправління

"Інформація про залежність за замовчуванням для проектів, які успадковують цей. Залежності в цьому розділі не усуваються негайно. Натомість, коли POM, похідний від цього, оголошує залежність, описану відповідними groupId та artifactId, версією та іншими значеннями з цього розділу використовуються для цієї залежності, якщо вони ще не були вказані. " [ https://maven.apache.org/ref/3.6.1/maven-model/maven.html ]

Його слід прочитати разом з додатковою інформацією, наявною на іншій сторінці:

".. мінімальний набір інформації для відповідності посилання на залежність до розділу" залежність управління "насправді {groupId, artifactId, тип, класифікатор}. У багатьох випадках ці залежності стосуватимуться артефактів jar без класифікатора. Це дозволяє нам скоротити ідентичність, встановлену на {groupId, artifactId}, оскільки типовим для поля типу є jar, а класифікатор за замовчуванням - null. " [ https://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html ]

Таким чином, всі піделементи (область, винятки тощо) елементу залежності - окрім groupId, artifactId, типу, класифікатора, а не просто версії - доступні для блокування / за замовчуванням у точці (і таким чином успадковуються від там далі) ви вказуєте залежність в залежності від елементу. Якщо ви вказали залежність із типом та класифікатором піделементів (див. Веб-сторінку, що цитує перше цитування, щоб перевірити всі піделементи) як jar та не нульову відповідно, вам знадобиться {groupId, artifactId, класифікатор, тип} посилатись (вирішувати) цю залежність у будь-якій точці спадщини, що походить від елемента управління залежністю. Інакше, {groupId, artifactId} буде достатньо, якщо ви не збираєтесь заміняти за замовчуванням класифікатор і тип (jar та null відповідно). Таким чином, за замовчуванням це ключове слово в цьому визначенні; будь-який піделемент (-и) (крім groupId,

Отже, будь-який елемент залежності, що знаходиться за межами залежності, керується незалежно від того, як посилання на якийсь елемент залежності управління або як окремий, негайно вирішується (тобто встановлюється у локальний сховище та доступний для класних шляхів).

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.