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


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.