Différences entre la gestion des dépendances et les dépendances dans Maven

768

Quelle est la difference entre dependencyManagementet dependencies? J'ai vu les documents sur le site Web d'Apache Maven. Il semble qu'une dépendance définie sous le dependencyManagementpuisse être utilisée dans ses modules enfants sans spécifier la version.

Par exemple:

Un projet parent (Pro-par) définit une dépendance sous dependencyManagement:

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

Puis chez l'enfant de Pro-par, je peux utiliser la junit:

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

Cependant, je me demande s'il est nécessaire de définir junit dans le pom parent? Pourquoi ne pas le définir directement dans le module nécessaire?

hguser
la source

Réponses:

465

La gestion des dépendances permet de consolider et de centraliser la gestion des versions de dépendance sans ajouter de dépendances héritées par tous les enfants. Ceci est particulièrement utile lorsque vous avez un ensemble de projets (c'est-à-dire plusieurs) qui hérite d'un parent commun.

Un autre cas d'utilisation extrêmement important dependencyManagementest le contrôle des versions des artefacts utilisés dans les dépendances transitives. C'est difficile à expliquer sans exemple. Heureusement, cela est illustré dans la documentation.

Pascal Thivent
la source
17
Donc, son besoin de déclarer les dépendances dans le pom du projet enfant de toute façon même s'ils ont déclaré dans le pom du projet parent dans la section <dependencyManagement>? Est-il possible de faire une sorte d'héritage de dépendances?
johnny-b-goode
56
Oui, vous devez toujours les définir dans le POM enfant pour montrer que vous les utilisez. Ils ne sont pas réellement inclus dans les projets enfants simplement parce qu'ils sont <dependencyManagement>dans le POM parent. Le fait d'inclure des dépendances dans <dependencyManagement>centralise la gestion de la version, de la portée et des exclusions de chaque dépendance, si et quand vous décidez de l'utiliser. Le guide de Maven sur la gestion des dépendances entre dans tous les détails.
hotshot309
2
Le deuxième paragraphe ( dependencyManagementcontrôle également les dépendances transitives) n'est vrai que lorsque les dépendances sont explicitement définies: stackoverflow.com/questions/28312975/…
Robert Metzger
2
@ johnny-b-goode Ce que vous pouvez encore faire est de créer une nouvelle dependenciessection dans votre pom parent. Nous l'avons fait pour que tous les projets enfants aient des apache-commons par défaut et pour ne pas les déclarer tout le temps.
рüффп
771

Je suis à la mode en retard à cette question, mais je pense que cela vaut une réponse plus claire que celle acceptée (ce qui est correct, mais ne met pas l'accent sur la partie importante réelle, que vous devez vous déduire).

Dans le POM parent, la principale différence entre le <dependencies>et <dependencyManagement>est la suivante:

Les artefacts spécifiés dans la <dependencies>section seront TOUJOURS inclus en tant que dépendance du ou des modules enfants.

Les artefacts spécifiés dans la <dependencyManagement>section ne seront inclus dans le module enfant que s'ils ont également été spécifiés dans la <dependencies>section du module enfant lui-même. Pourquoi est-il bon de demander car vous spécifiez la version et / ou la portée dans le parent et vous pouvez les laisser de côté lorsque vous spécifiez les dépendances dans le POM enfant. Cela peut vous aider à utiliser des versions unifiées pour les dépendances des modules enfants, sans spécifier la version dans chaque module enfant.

dcoder
la source
1
Mais n'est-ce pas aussi un peu une surcharge, en utilisant <dependencyManagement>over <dependencies>dans la racine .pom? Les enfants pompourraient être beaucoup plus courts.
Janez Kuhar
18
C'est vrai. L'utilisation de <dépendances> au lieu de <gestion des dépendances> créera des poms enfants plus courts. Cependant, cela a un coût - cela signifie que ces dépendances seront TOUJOURS définies pour TOUS les modules enfants. Si seuls CERTAINS des modules enfants ont besoin d'une certaine dépendance, l'utilisation de "<dependencyManagement>" à la place vous permettrait de choisir les modules enfants qui auront cette dépendance, tout en étant un peu efficace en définissant la version de la dépendance uniquement dans le pom parent.
dcoder
2
@JanezKuhar Il est logique pour moi que si vous spécifiez une dépendance dans le module enfant, elle remplacera celle du parent, mais j'avoue que je ne m'en souviens pas. Je devrai vérifier les documents maven pour celui-là quand j'en aurai l'occasion. Bien qu'il soit plus facile de simplement configurer un projet parent-enfant simple et de vérifier :)
dcoder
26
Bonne explication pour un concept simple - pourquoi est-il si difficile pour Maven d'expliquer aussi facilement son propre outil?
jimmy_terra
1
J'ajouterais Artifacts specified in the <dependencies> section will ALWAYS be included as a dependency of the child module(s)qu'ils sont également inclus dans le parent. Il semble impossible de définir une dépendance pour les enfants, mais pas pour le parent.
caducée
54

La documentation sur le site Maven est horrible. Ce que dependencyManagement fait, c'est simplement déplacer vos définitions de dépendances (version, exclusions, etc.) vers le pom parent, puis dans les poms enfants, il vous suffit de mettre groupId et artifactId. C'est tout (sauf pour le chaînage de pom parent et autres, mais ce n'est pas vraiment compliqué non plus - dependencyManagement l'emporte sur les dépendances au niveau parent - mais si vous avez une question à ce sujet ou importe, la documentation Maven est un peu meilleure).

Après avoir lu toutes les ordures «a», «b», «c» sur le site de Maven et être confus, j'ai réécrit leur exemple. Donc, si vous aviez 2 projets (proj1 et proj2) qui partagent une dépendance commune (betaShared), vous pouvez déplacer cette dépendance vers le pom parent. Pendant que vous y êtes, vous pouvez également déplacer vers le haut toutes les autres dépendances (alpha et charlie) mais uniquement si cela a du sens pour votre projet. Donc, pour la situation décrite dans les phrases précédentes, voici la solution avec dependencyManagement dans le pom parent:

<!-- 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
la source
2
Question quelque peu hors sujet: que signifie le type de dépendance "barre"? J'ai vu un exemple de pom sur la documentation Maven mais je n'ai pas trouvé de définition. J'ai supposé que c'était une faute de frappe de «guerre» ou de «pot», mais je le vois dans d'autres exemples tels que le vôtre.
NobodyMan
NobodyMan - Il ne s'agit donc que d'un espace réservé pour un autre type d'archive. Comme utiliser "foo". Ou il pourrait être utilisé si quelqu'un a fait un type personnalisé avec l'extension «bar». Et il existe de nombreux types d'archives obscures. Comme sar, qui est l'archive du service jboss.
MattC
Votre exemple est assez clair et réaffirme ce que j'avais moi-même cherché dans la documentation. L'avez-vous soumis au projet Maven? Après avoir étudié votre exemple, je me prépare à simplifier un POM qui a les deux, et n'a besoin que de déclarations de dépendance, puisque le projet auquel il est associé n'a pas d'enfants.
David A. Gray
Eh bien, j'étais sur le point de supprimer le nœud DependencyManagement, jusqu'à ce qu'il me vienne à l'esprit que le laisser me permet d'établir une version minimale pour tous les POM enfants qui se retrouvent indirectement dans l'arborescence des dépendances. Par exemple, en poursuivant javax.cache.cache-apI, j'ai découvert une version 1.0.0 sensiblement plus récente (par rapport à 0.3.0) qui pourrait également être utilisée tout au long.
David A. Gray
Cette explication est parfaite.
Smart Coder
45

C'est comme vous l'avez dit; dependencyManagementest utilisé pour extraire toutes les informations de dépendance dans un fichier POM commun, simplifiant les références dans le fichier POM enfant.

Cela devient utile lorsque vous avez plusieurs attributs que vous ne souhaitez pas retaper dans plusieurs projets enfants.

Enfin, dependencyManagementpeut être utilisé pour définir une version standard d'un artefact à utiliser dans plusieurs projets.

Pran
la source
4
Ainsi, les dépendances ne héritent pas? Son besoin d'être déclaré dans le pom du projet enfant de toute façon?
johnny-b-goode
6
Oui, vous devez quand même les déclarer dans les projets enfants, mais sans spécifier de version.
Pavel Vlasov
Ce scénario est utile lorsque vous souhaitez avoir la gouvernance des versions dans plusieurs projets java ayant une relation parent-enfant.
Anuj Kumar
43

Il y a encore une chose qui n'est pas suffisamment mise en évidence, à mon avis, et c'est l' héritage indésirable .

Voici un exemple incrémentiel:

Je déclare dans mon parentpom:

<dependencies>
        <dependency>
            <groupId>com.google.guava</groupId>
            <artifactId>guava</artifactId>
            <version>19.0</version>
        </dependency>
</dependencies>

boom! Je l' ai dans mes Child A, Child Bet Child Cmodules:

  • Implicité héritée des enfants pompons
  • Un seul endroit pour gérer
  • Pas besoin de redéclarer quoi que ce soit dans les pompons pour enfants
  • Je peux encore redelcare et override à version 18.0un Child Bsi je veux.

Mais que se passe-t-il si je finis par ne pas avoir besoin de goyave Child C, ni à l'avenir Child Dni de Child Emodules?

Ils en hériteront toujours et ce n'est pas souhaité! C'est exactement comme l'odeur du code Java God Object, où vous héritez de quelques bits utiles d'une classe, ainsi que d'une tonne de choses indésirables.

C'est là <dependencyManagement>qu'entre en jeu. Lorsque vous ajoutez cela à votre pom parent, tous vos modules enfants ARRÊTENT de le voir . Et donc vous êtes obligé d'aller dans chaque module individuel qui en a besoin et de le déclarer à nouveau ( Child Aet Child B, sans la version cependant).

Et, évidemment, vous ne le faites pas pour Child C, et donc votre module reste léger.

Andrejs
la source
Les dépendances mentionnées dans <dependencyManagement> seront-elles téléchargées pour le projet parent pom?
Jaspreet Jolly
Êtes-vous sûr que si nous utilisons <dependencyManagement>dans le pom parent, par défaut, les dépendances ne seront pas héritées dans les poms enfants? Parce que dans le doc: maven.apache.org/guides/introduction/… tout en expliquant la deuxième utilisation du <dependencyManagement>il semble qu'il sera hérité par défaut. Sur une ligne, ils disent que: "Lorsque maven est exécuté sur le projet B, la version 1.0 des artefacts a, b, c et d sera utilisée quelle que soit la version spécifiée dans leur pom" même si "b" n'est pas utilisé dans le projet B
chirag soni
Essayez-le vous
Andrejs
17

Il y a quelques réponses décrivant les différences entre <depedencies>et les <dependencyManagement>balises avec maven.

Cependant, quelques points développés ci-dessous de manière concise:

  1. <dependencyManagement>permet de consolider toutes les dépendances (utilisées au niveau du pom enfant) utilisées sur différents modules - clarté , gestion centralisée des versions des dépendances
  2. <dependencyManagement>permet de mettre à niveau / rétrograder facilement les dépendances en fonction des besoins, dans un autre scénario, cela doit être exercé à chaque niveau de pom enfant - cohérence
  3. les dépendances fournies dans la <dependencies>balise sont toujours importées, tandis que les dépendances fournies <dependencyManagement>dans le parent pom ne seront importées que si le pom enfant a une entrée respective dans sa <dependencies>balise.
Amit Kaneria
la source
17

Désolé, je suis très en retard à la fête.

Permettez-moi d'essayer d'expliquer la différence en utilisant la mvn dependency:treecommande

Considérez l'exemple ci-dessous

Parent POM - Mon projet

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

Child POM - module de données

<dependencies>
    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-lang3</artifactId>
    </dependency>
</dependencies>

Child POM - module d'application (n'a pas de dépendance supplémentaire, donc laisser les dépendances vides)

 <dependencies>
</dependencies>

Lors de l'exécution de la mvn dependency:treecommande, nous obtenons le résultat suivant

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 goyave est répertorié comme dépendance dans chaque module (y compris le parent), tandis que l' apache commons est répertorié comme dépendance uniquement dans le module de données (pas même dans le module parent)

IamVickyAV
la source
11

Si la dépendance a été définie dans l'élément dependencyManagement du pom de niveau supérieur, le projet enfant n'a pas dû répertorier explicitement la version de la dépendance. si le projet enfant définissait une version, il remplacerait la version répertoriée dans la section dependencyManagement du POM de niveau supérieur. Autrement dit, la version dependencyManagement n'est utilisée que lorsque l'enfant ne déclare pas directement une version.

Mustafa Güven
la source
1
Je pense que cette affirmation n'est peut-être pas correcte. Dans les exemples de gestion des dépendances de Maven (# 2), ils disent que les dépendances définies dans un pom parent avec une version, remplaceront la version spécifiée dans le pom enfant: "Lorsque maven est exécuté sur le projet B version 1.0 des artefacts a, b, c , et d sera utilisé quelle que soit la version spécifiée dans leur pom. "
devdanke
@devdanke Au moins, les problèmes de Eclipse M2e un avertissement: d' PRÉPONDÉRANTS géré la version ... pour ... .
GeroldBroser réintègre Monica le
4

Dans le POM parent, la principale différence entre le <dependencies>et <dependencyManagement>est la suivante:

Les artefacts spécifiés dans la <dependencies>section seront TOUJOURS inclus en tant que dépendance du ou des modules enfants.

Les artefacts spécifiés dans la section ne seront inclus dans le module enfant que s'ils ont également été spécifiés dans la section du module enfant lui-même. Pourquoi est-il bon de demander? car vous spécifiez la version et / ou la portée dans le parent et vous pouvez les laisser de côté lorsque vous spécifiez les dépendances dans le POM enfant. Cela peut vous aider à utiliser des versions unifiées pour les dépendances des modules enfants, sans spécifier la version dans chaque module enfant.

Yaver
la source
4

Dans mes propres mots, votre parent-projectaide vous fournit 2 types de dépendances:

  • dépendances implicites : toutes les dépendances définies dans la <dependencies>section de votre parent-projectsont héritées par tous leschild-projects
  • dépendances explicites : permet de sélectionner, les dépendances à appliquer dans votre child-projects. Ainsi, vous utilisez la <dependencyManagement>section, pour déclarer toutes les dépendances que vous allez utiliser dans vos différents child-projects. La chose la plus importante est que, dans cette section, vous définissez un <version>afin que vous n'ayez pas à le déclarer à nouveau dans votre child-project.

Le <dependencyManagement>point de vue (corrigez-moi si je me trompe) est juste utile en vous aidant à centraliser la version de vos dépendances. C'est comme une sorte de fonction d'aide.

Harry Coder
la source
1

Dans Eclipse, il existe une autre fonctionnalité dans le dependencyManagement. Quand dependenciesest utilisé sans lui, les dépendances non trouvées sont notées dans le fichier pom. Si dependencyManagementest utilisé, les dépendances non résolues restent inaperçues dans le fichier pom et les erreurs n'apparaissent que dans les fichiers java. (importations et autres ...)

Gangnus
la source
1

La différence entre les deux est mieux apportée dans ce qui semble une définition nécessaire et suffisante de l'élément dependencyManagement disponible dans les documents du site Web Maven:

dependencyManagement

"Informations de dépendance par défaut pour les projets qui héritent de celui-ci. Les dépendances de cette section ne sont pas immédiatement résolues. Au lieu de cela, lorsqu'un POM dérivé de celui-ci déclare une dépendance décrite par un groupId et un artifactId correspondants, la version et d'autres valeurs de cette section sont utilisés pour cette dépendance s'ils ne sont pas déjà spécifiés. " [ https://maven.apache.org/ref/3.6.1/maven-model/maven.html ]

Il doit être lu avec plus d'informations disponibles sur une autre page:

«..L'ensemble minimal d'informations pour faire correspondre une référence de dépendance à une section dependencyManagement est en fait {groupId, artifactId, type, classifier}. Dans de nombreux cas, ces dépendances feront référence à des artefacts jar sans classificateur. Cela nous permet de raccourcir l'identité définie sur {groupId, artifactId}, car la valeur par défaut pour le champ type est jar et le classificateur par défaut est null. " [ https://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html ]

Ainsi, tous les sous-éléments (portée, exclusions, etc.) d'un élément de dépendance - autres que groupId, artifactId, type, classifier, et pas seulement la version - sont disponibles pour le verrouillage / par défaut au point (et donc hérités de à partir de là) vous spécifiez la dépendance dans un élément dependencyElement. Si vous aviez spécifié une dépendance avec les sous-éléments type et classifier (voir la première page Web citée pour vérifier tous les sous-éléments) comme non jar et non null respectivement, vous auriez besoin de {groupId, artifactId, classifier, type} pour référencer (résoudre) cette dépendance à tout moment dans un héritage provenant de l'élément dependencyManagement. Sinon, {groupId, artifactId} suffirait si vous n'avez pas l'intention de remplacer les valeurs par défaut pour le classificateur et le type (jar et null respectivement). Par défaut, c'est un bon mot-clé dans cette définition; tout sous-élément (autre que groupId,

Ainsi, tout élément de dépendance en dehors de dependencyManagement, que ce soit en tant que référence à un élément de dependencyManagement ou en tant que autonome est immédiatement résolu (c'est-à-dire installé dans le référentiel local et disponible pour les chemins de classe).

rps
la source