Diferencias entre dependencia Gestión y dependencias en Maven

768

¿Cuál es la diferencia entre dependencyManagementy dependencies? He visto los documentos en el sitio web de Apache Maven. Parece que una dependencia definida bajo el dependencyManagementse puede utilizar en sus módulos secundarios sin especificar la versión.

Por ejemplo:

Un proyecto padre (Pro-par) define una dependencia bajo dependencyManagement:

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

Luego, en el hijo de Pro-par, puedo usar el junit:

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

Sin embargo, me pregunto si es necesario definir junit en el pom padre. ¿Por qué no definirlo directamente en el módulo necesario?

Hguser
fuente

Respuestas:

464

Dependency Management permite consolidar y centralizar la gestión de versiones de dependencia sin agregar dependencias que son heredadas por todos los hijos. Esto es especialmente útil cuando tiene un conjunto de proyectos (es decir, más de uno) que hereda un padre común.

Otro caso de uso extremadamente importante dependencyManagementes el control de versiones de artefactos utilizados en dependencias transitivas. Esto es difícil de explicar sin un ejemplo. Afortunadamente, esto se ilustra en la documentación.

Pascal Thivent
fuente
17
Entonces, ¿es necesario declarar dependencias en los pom del proyecto hijo de todos modos, incluso si lo declararon en el pom del proyecto principal en la sección <dependencyManagement>? ¿Es posible hacer algún tipo de herencia de dependencias?
johnny-b-goode
55
Sí, aún necesita definirlos en el POM secundario para mostrar que los está usando. En realidad, no se incluyen en los proyectos secundarios solo porque están <dependencyManagement>en el POM principal. La inclusión de dependencias en <dependencyManagement>la gestión centralizada de la versión, el alcance y las exclusiones para cada dependencia, si decide utilizarla y cuándo. La guía de Maven para la gestión de dependencias entra en todos los detalles.
hotshot309
2
El segundo párrafo ( dependencyManagementtambién controla las dependencias transitivas) solo es cierto cuando las dependencias se establecen explícitamente: stackoverflow.com/questions/28312975/…
Robert Metzger
2
@ johnny-b-goode Lo que aún puede hacer es crear una nueva dependenciessección en su pom padre. Lo hicimos para que todos los proyectos secundarios tengan algunos apache-commons por defecto y no declararlos todo el tiempo.
рüффп
771

Llego tarde a esta pregunta, pero creo que merece una respuesta más clara que la aceptada (lo cual es correcto, pero no enfatiza la parte importante real, que debes deducir).

En el POM padre, la principal diferencia entre <dependencies>y <dependencyManagement>es esta:

Los artefactos especificados en la <dependencies>sección SIEMPRE se incluirán como una dependencia de los módulos secundarios.

Los artefactos especificados en la <dependencyManagement>sección solo se incluirán en el módulo secundario si también se especificaron en la <dependencies>sección del propio módulo secundario. ¿Por qué es bueno lo preguntas? porque especifica la versión y / o el alcance en el elemento primario y puede omitirlos al especificar las dependencias en el POM secundario. Esto puede ayudarlo a usar versiones unificadas para dependencias para módulos secundarios, sin especificar la versión en cada módulo secundario.

dcoder
fuente
1
Pero, ¿no es también un poco una sobrecarga, usar <dependencyManagement>más <dependencies>en la raíz .pom? El niño pompuede ser mucho más bajo.
Janez Kuhar
18
Es verdad. El uso de <dependencies> en lugar de <dependencyManagement> creará poms secundarios más cortos. Sin embargo, tiene un costo, significa que esas dependencias SIEMPRE se definirán para TODOS los módulos secundarios. Si solo ALGUNOS de los módulos secundarios necesitan una cierta dependencia, el uso de "<dependencyManagement>" en su lugar le permitiría elegir qué módulos secundarios tendrán esa dependencia, y aún será un poco eficiente al configurar la versión de dependencia solo en el pom padre.
dcoder
2
@JanezKuhar Para mí tiene sentido que si especificas una dependencia en el módulo hijo, anulará la del padre, pero admito que no me acuerdo. Tendré que revisar los documentos de Maven para ese cuando tenga la oportunidad. Aunque podría ser más fácil simplemente configurar un proyecto simple padre-hijo y verificar :)
dcoder
26
Buena explicación para un concepto simple: ¿por qué parece tan difícil para Maven explicar su propia herramienta tan fácilmente?
jimmy_terra
1
Agregaría Artifacts specified in the <dependencies> section will ALWAYS be included as a dependency of the child module(s)que también están incluidos en el padre. Parece que no es posible establecer una dependencia para los hijos, pero no para el padre.
caduceo
54

La documentación en el sitio de Maven es horrible. Lo que hace dependencyManagement es simplemente mover sus definiciones de dependencia (versión, exclusiones, etc.) al pom padre, luego en los poms secundarios solo tiene que poner groupId y artifactId. Eso es todo (excepto el encadenamiento de pom padres y similares, pero eso tampoco es realmente complicado: dependencyManagement vence a las dependencias en el nivel primario, pero si tiene alguna pregunta sobre eso o importaciones, la documentación de Maven es un poco mejor).

Después de leer toda la basura 'a', 'b', 'c' en el sitio de Maven y confundirme, reescribí su ejemplo. Entonces, si tenía 2 proyectos (proj1 y proj2) que comparten una dependencia común (betaShared), podría mover esa dependencia al pom padre. Mientras lo hace, también puede subir cualquier otra dependencia (alfa y charlie) pero solo si tiene sentido para su proyecto. Entonces, para la situación descrita en las oraciones anteriores, aquí está la solución con dependencyManagement en el padre 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
fuente
2
Pregunta algo fuera de tema: ¿qué significa el tipo de dependencia "barra"? Vi en un ejemplo pom en la documentación de Maven pero no pude encontrar una definición. Supuse que era un error tipográfico de "guerra" o "frasco", pero lo veo en otros ejemplos como el suyo.
NobodyMan
NobodyMan: por lo tanto, es solo un marcador de posición para otro tipo de archivo. Como usar 'foo'. O podría usarse si alguien hizo un tipo personalizado con la extensión 'barra'. Y hay muchos tipos de archivos oscuros por ahí. Como sar, que es el archivo de servicio jboss.
MattC
Su ejemplo es bastante claro y reafirma lo que había asimilado por mi cuenta en la documentación. ¿Lo has enviado al proyecto Maven? Después de estudiar su ejemplo, me estoy preparando para simplificar un POM que tiene ambas, y solo necesita declaraciones de dependencia, ya que el proyecto con el que está asociado no tiene hijos.
David A. Gray
Bueno, estaba a punto de abandonar el nodo DependencyManagement, hasta que se me ocurrió que dejarlo me permite establecer una versión mínima para cualquier POM secundario que encuentre su camino en el árbol de dependencia indirectamente. Como ejemplo, al perseguir javax.cache.cache-apI, descubrí una versión 1.0.0 significativamente más nueva (versus 0.3.0) que también podría usarse en todo momento.
David A. Gray
Esta explicación es perfecta.
Smart Coder
45

Es como dijiste; dependencyManagementse utiliza para extraer toda la información de dependencia en un archivo POM común, simplificando las referencias en el archivo POM secundario.

Se vuelve útil cuando tiene múltiples atributos que no desea volver a escribir en múltiples proyectos secundarios.

Finalmente, dependencyManagementse puede usar para definir una versión estándar de un artefacto para usar en múltiples proyectos.

Pran
fuente
44
Entonces, las dependencias no hereda? ¿Es necesario declararlo en el pom del proyecto hijo de todos modos?
johnny-b-goode
66
Sí, debe declararlos de todos modos en proyectos secundarios, pero sin especificar una versión.
Pavel Vlasov
Este escenario es útil cuando desea tener la gobernanza de versiones en múltiples proyectos java que tienen una relación padre-hijo.
Anuj Kumar
43

Todavía hay una cosa que no se destaca lo suficiente, en mi opinión, y que es la herencia no deseada .

Aquí hay un ejemplo incremental:

Declaro en mi parentpom:

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

¡auge! Lo tengo en mi Child A, Child By Child Cmódulos:

  • Implicidad heredada por niños poms
  • Un solo lugar para administrar
  • No es necesario volver a declarar nada en niños poms
  • Todavía puedo volver a cuidar y anular version 18.0en un Child Bsi quiero.

Pero, ¿qué pasa si termino sin necesitar guayaba Child C, y tampoco en el futuro Child Dy los Child Emódulos?

¡Todavía lo heredarán y esto no es deseado! Esto es como el olor del código de objeto de Dios Java, donde heredas algunos bits útiles de una clase, y también una tonelada de cosas no deseadas.

Aquí es donde <dependencyManagement>entra en juego. Cuando agrega esto a su pom padre, todos sus módulos secundarios DEJAN de verlo . Y por lo tanto, se ve obligado a entrar en cada módulo individual que lo necesita y declararlo nuevamente ( Child Ay Child B, sin embargo, sin la versión).

Y, obviamente, no lo hace Child C, y por lo tanto su módulo sigue siendo delgado.

Andrejs
fuente
¿Las dependencias mencionadas en <dependencyManagement> se descargarán para el proyecto pom padre?
Jaspreet Jolly el
¿Está seguro de que si usamos <dependencyManagement>en el pom padre, por defecto, las dependencias no se heredarán en los poms secundarios? Porque en el documento: maven.apache.org/guides/introduction/… mientras se explica el segundo uso del <dependencyManagement>parece que se heredará de forma predeterminada. En una línea dicen que: "Cuando Maven se ejecuta en el proyecto B, la versión 1.0 de los artefactos a, b, c y d se usará independientemente de la versión especificada en su pom" aunque "b" no se use en el proyecto B
chirag soni
Pruébelo usted mismo
Andrejs
17

Hay algunas respuestas que describen las diferencias <depedencies>y las <dependencyManagement>etiquetas con Maven.

Sin embargo, algunos puntos se detallan a continuación de manera concisa:

  1. <dependencyManagement>permite consolidar todas las dependencias (utilizadas a nivel de pom hijo) utilizadas en diferentes módulos: claridad , gestión de versiones de dependencia central
  2. <dependencyManagement>permite actualizar / degradar dependencias fácilmente según la necesidad, en otro escenario, esto debe ejercerse en cada nivel de pom infantil: consistencia
  3. las dependencias proporcionadas en la <dependencies>etiqueta siempre se importan, mientras que las dependencias proporcionadas <dependencyManagement>en el pom principal se importarán solo si el pom secundario tiene una entrada respectiva en su <dependencies>etiqueta.
Amit Kaneria
fuente
17

Lo siento, llego muy tarde a la fiesta.

Déjame intentar explicar la diferencia usando mvn dependency:tree comando

Considere el siguiente ejemplo

Parent POM - My Project

<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 - módulo de datos

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

Child POM - módulo de aplicación (no tiene dependencia adicional, por lo que deja las dependencias vacías)

 <dependencies>
</dependencies>

Al ejecutar el mvn dependency:treecomando, obtenemos el siguiente resultado

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 aparece como dependencia en todos los módulos (incluido el padre), mientras que apache commons aparece como dependencia solo en el módulo de datos (ni siquiera en el módulo padre)

IamVickyAV
fuente
11

Si la dependencia se definió en el elemento de gestión de dependencia del pom de nivel superior, el proyecto secundario no tenía que enumerar explícitamente la versión de la dependencia. si el proyecto secundario definió una versión, anularía la versión que figura en la sección de gestión de dependencias del POM de nivel superior. Es decir, la versión de dependencyManagement solo se usa cuando el hijo no declara una versión directamente.

Mustafa Güven
fuente
1
Creo que esta afirmación puede no ser correcta. En los ejemplos de Maven's Dependency Management (# 2), dicen que las dependencias definidas en un pom padre con una versión, anularán la versión especificada en el pom hijo: "Cuando maven se ejecuta en el proyecto B versión 1.0 de los artefactos a, b, c , yd se usarán independientemente de la versión especificada en su pom ".
devdanke
@devdanke Al menos, las cuestiones Eclipse M2e una advertencia: Alteración temporal gestionados de la versión para ... ... .
GeroldBroser reintegra a Mónica el
4

En el POM padre, la principal diferencia entre <dependencies>y <dependencyManagement>es esta:

Artefactos especificados en el <dependencies>sección SIEMPRE se incluirán como una dependencia de los módulos secundarios.

Los artefactos especificados en la sección solo se incluirán en el módulo secundario si también se especificaron en la sección del propio módulo secundario. ¿Por qué es bueno lo preguntas? porque especifica la versión y / o el alcance en el elemento primario, y puede omitirlos al especificar las dependencias en el POM secundario. Esto puede ayudarlo a usar versiones unificadas para dependencias de módulos secundarios, sin especificar la versión en cada módulo secundario.

Yaver
fuente
4

Solo en mis propias palabras, tu parent-projectayuda a proporcionar 2 tipos de dependencias:

  • dependencias implícitas : todas las dependencias definidas en la <dependencies>sección en tu parent-projectson heredadas por todos loschild-projects
  • dependencias explícitas : le permite seleccionar las dependencias para aplicar en su child-projects. Por lo tanto, usa la <dependencyManagement>sección, para declarar todas las dependencias que va a usar en sus diferentes child-projects. Lo más importante es que, en esta sección, defina un <version>para que no tenga que volver a declararlo en su child-project.

En <dependencyManagement>mi punto de vista (corrígeme si estoy equivocado) es útil al ayudarte a centralizar la versión de tus dependencias. Es como una especie de función auxiliar.

Harry Coder
fuente
1

En Eclipse, hay una característica más en el dependencyManagement. Cuando dependenciesse usa sin él, las dependencias no encontradas se notan en el archivo pom. Si dependencyManagementse usa, las dependencias no resueltas pasan desapercibidas en el archivo pom y los errores solo aparecen en los archivos java. (importaciones y tal ...)

Gangnus
fuente
1

La diferencia entre los dos se presenta mejor en lo que parece una definición necesaria y suficiente del elemento de dependencia de gestión disponible en los documentos del sitio web de Maven:

gestión de dependencia

"Información de dependencia predeterminada para proyectos que heredan de este. Las dependencias en esta sección no se resuelven de inmediato. En cambio, cuando un POM derivado de este declara una dependencia descrita por un groupId y artifactId coincidentes, la versión y otros valores de esta sección se usan para esa dependencia si aún no se especificaron ". [ https://maven.apache.org/ref/3.6.1/maven-model/maven.html ]

Debe leerse junto con más información disponible en una página diferente:

"... el conjunto mínimo de información para hacer coincidir una referencia de dependencia con una sección de gestión de dependencia es en realidad {groupId, artifactId, type, classifier}. En muchos casos, estas dependencias se referirán a artefactos jar sin clasificador. Esto nos permite abreviar la identidad establecida en {groupId, artifactId}, ya que el valor predeterminado para el campo de tipo es jar, y el clasificador predeterminado es nulo ". [ https://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html ]

Por lo tanto, todos los subelementos (alcance, exclusiones, etc.) de un elemento de dependencia, que no sean groupId, artifactId, type, clasifier, no solo version, están disponibles para bloqueo / default en el punto (y por lo tanto se heredan de allí adelante) usted especifica la dependencia dentro de un dependencyElement. Si hubiera especificado una dependencia con los subelementos de tipo y clasificador (consulte la primera página web citada para verificar todos los subelementos) como no jar y no nulo respectivamente, necesitaría {groupId, artifactId, classifier, type} para hacer referencia (resolver) esa dependencia en cualquier punto de una herencia que se origina en el elemento dependencyManagement. De lo contrario, {groupId, artifactId} sería suficiente si no tiene la intención de anular los valores predeterminados para clasificador y tipo (jar y null respectivamente). Entonces, el valor predeterminado es una buena palabra clave en esa definición; cualquier subelemento (s) (distinto de groupId,

Por lo tanto, cualquier elemento de dependencia fuera de dependencyManagement, ya sea como referencia a algún elemento de dependencyManagement o como independiente, se resuelve de inmediato (es decir, se instala en el repositorio local y está disponible para classpaths).

rps
fuente