Diferenças entre dependencyManagement e dependências no Maven

766

Qual é a diferença entre dependencyManagemente dependencies? Eu vi os documentos no site do Apache Maven. Parece que uma dependência definida sob o dependencyManagementpode ser usada em seus módulos filhos sem especificar a versão.

Por exemplo:

Um projeto pai (Pro-par) define uma dependência sob o dependencyManagement:

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

Então, no filho do Pro-par, posso usar o junit:

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

No entanto, gostaria de saber se é necessário definir junit no pom pai? Por que não defini-lo diretamente no módulo necessário?

hguser
fonte

Respostas:

464

O Gerenciamento de Dependências permite consolidar e centralizar o gerenciamento de versões de dependência sem adicionar dependências herdadas por todos os filhos. Isso é especialmente útil quando você tem um conjunto de projetos (ou seja, mais de um) que herda um pai comum.

Outro caso de uso extremamente importante dependencyManagementé o controle de versões de artefatos usados ​​em dependências transitivas. Isso é difícil de explicar sem um exemplo. Felizmente, isso é ilustrado na documentação.

Pascal Thivent
fonte
17
Portanto, é necessário declarar dependências no pom do projeto filho de qualquer maneira, mesmo se declaradas no pom do projeto pai na seção <dependencyManagement>? É possível fazer algum tipo de herança de dependências?
johnny-b-Goode
55
Sim, você ainda precisa defini-los no POM filho para mostrar que você os está usando. Na verdade, eles não são incluídos nos projetos filhos apenas porque estão no <dependencyManagement>POM pai. Incluir dependências no <dependencyManagement>gerenciamento centralizado da versão, escopo e exclusões de cada dependência, se e quando você decidir usá-lo. O guia do Maven para gerenciamento de dependências entra em todos os detalhes.
Hotshot309 13/09/12
2
O segundo parágrafo ( dependencyManagementtambém controla dependências transitivas) só é verdadeiro quando as dependências são definidas explicitamente: stackoverflow.com/questions/28312975/…
Robert Metzger
2
@ johnny-b-goode O que você ainda pode fazer é criar uma nova dependenciesseção no seu pom pai. Fizemos isso para que todo projeto filho tivesse alguns apache-commons por padrão e não os declarasse o tempo todo.
рüффп
771

Estou atrasado na moda para essa pergunta, mas acho que vale uma resposta mais clara do que a aceita (o que é correto, mas não enfatiza a parte realmente importante, que você precisa deduzir a si mesmo).

No POM pai, a principal diferença entre o <dependencies>e <dependencyManagement>é esta:

Os artefatos especificados na <dependencies>seção SEMPRE serão incluídos como uma dependência do (s) módulo (s) filho (s).

Os artefatos especificados na <dependencyManagement>seção serão incluídos apenas no módulo filho se também tiverem sido especificados na <dependencies>seção do próprio módulo filho. Por que é bom você perguntar? porque você especifica a versão e / ou escopo no pai e pode deixá-los de fora ao especificar as dependências no POM filho. Isso pode ajudá-lo a usar versões unificadas para dependências para módulos filhos, sem especificar a versão em cada módulo filho.

dcoder
fonte
1
Mas não é também um pouco de sobrecarga, usando <dependencyManagement>mais <dependencies>na raiz .pom? As crianças pompodem ser muito mais curtas.
Janez Kuhar
18
Isso é verdade. Usar <dependências> em vez de <dependencyManagement> criará filhos menores. No entanto, ele tem um custo - significa que essas dependências SEMPRE serão definidas para TODOS os módulos filhos. Se apenas alguns dos módulos filhos precisarem de uma certa dependência, o uso de "<dependencyManagement>" permitirá que você escolha quais módulos filhos terão essa dependência e ainda será um pouco eficiente definindo a versão da dependência apenas no pom pai.
dcoder
2
@JanezKuhar Faz sentido para mim que, se você especificar uma dependência no módulo filho, ela substituirá a do pai, mas admito que não me lembro. Vou ter que verificar a documentação do maven quando tiver a chance. Embora possa ser mais fácil simplesmente configurar um projeto pai-filho simples e verificar :)
dcoder
26
Boa explicação para um conceito simples - por que parece tão difícil para o Maven explicar sua própria ferramenta com tanta facilidade?
jimmy_terra
1
Eu acrescentaria Artifacts specified in the <dependencies> section will ALWAYS be included as a dependency of the child module(s)que eles também estão incluídos nos pais. Parece que não é possível definir uma dependência para os filhos, mas não para os pais.
caduceus
54

A documentação no site do Maven é horrível. O que o dependencyManagement faz é simplesmente mover suas definições de dependência (versão, exclusões, etc.) para o pom pai e, em seguida, nos poms filhos, basta colocar o groupId e o artifactId. É isso aí (exceto para o encadeamento pai pom e afins, mas isso também não é realmente complicado - o dependencyManagement vence as dependências no nível pai - mas se tiver alguma dúvida sobre isso ou as importações, a documentação do Maven é um pouco melhor).

Depois de ler todo o lixo 'a', 'b', 'c' no site do Maven e ficar confuso, reescrevi o exemplo deles. Portanto, se você tiver 2 projetos (proj1 e proj2) que compartilham uma dependência comum (betaShared), poderá movê-la para o pom pai. Enquanto você está nisso, você também pode mover quaisquer outras dependências (alpha e charlie), mas apenas se isso fizer sentido para o seu projeto. Portanto, para a situação descrita nas frases anteriores, eis a solução com dependencyManagement no pom pai:

<!-- 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
fonte
2
Pergunta um tanto fora de tópico: o que significa tipo de dependência "bar"? Eu vi em um exemplo pom na documentação do Maven, mas não consegui encontrar uma definição. Supus que fosse um erro de digitação de "guerra" ou "jar", mas vejo isso em outros exemplos como o seu.
NobodyMan
NobodyMan - Portanto, é apenas um espaço reservado para outro tipo de arquivo. Como usar 'foo'. Ou poderia ser usado se alguém fizesse um tipo personalizado com a extensão 'bar'. E existem muitos tipos de arquivos obscuros por aí. Como o sar, que é o arquivo de serviço do jboss.
MattC
Seu exemplo é bastante claro e reafirma o que eu havia grunhado sozinho na documentação. Você o enviou ao projeto Maven? Tendo estudado seu exemplo, estou me preparando para simplificar um POM que possui ambos e precisa apenas de declarações de dependência, pois o projeto ao qual está associado não tem filhos.
David A. Gray
Bem, eu estava prestes a descartar o nó DependencyManagement, até que me ocorreu que deixar permitisse estabelecer uma versão mínima para qualquer POMs filho que encontrasse indiretamente a árvore de dependência. Como exemplo, na busca pelo javax.cache.cache-apI, descobri uma versão 1.0.0 significativamente mais nova (versus 0.3.0) que também pode ser usada por toda parte.
David A. Gray
Essa explicação é perfeita.
Smart Coder
45

É como você disse; dependencyManagementé usado para extrair todas as informações de dependência em um arquivo POM comum, simplificando as referências no arquivo POM filho.

Torna-se útil quando você tem vários atributos nos quais não deseja digitar novamente em vários projetos filhos.

Finalmente, dependencyManagementpode ser usado para definir uma versão padrão de um artefato para uso em vários projetos.

Pran
fonte
4
Então, dependências não herdadas? Sua necessidade de ser declarada no pom do projeto filho, afinal?
johnny-b-Goode
6
Sim, você precisa declará-los de qualquer maneira em projetos filhos, mas sem especificar uma versão.
Pavel Vlasov 13/01
Este cenário é útil quando você deseja ter controle de versões em vários projetos java que têm relacionamento pai-filho.
Anuj Kumar
43

Ainda há uma coisa que não está destacada o suficiente, na minha opinião, e que é herança indesejada .

Aqui está um exemplo incremental:

Eu declaro em meu parentpom:

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

estrondo! Eu tenho isso no meu Child A, Child Be Child Cmódulos:

  • Implicilidade herdada dos filhos-filhos
  • Um único local para gerenciar
  • Não há necessidade de redeclarar nada nos poms infantis
  • Ainda posso voltar a cuidar e substituir version 18.0em Child Bse quiser.

Mas e se eu acabar não precisando de goiaba Child Ce nem no futuro Child De Child Emódulos?

Eles ainda a herdarão e isso é indesejável! É como o cheiro do código Java God Object, no qual você herda alguns bits úteis de uma classe e também uma tonelada de coisas indesejadas.

É aqui que <dependencyManagement>entra em jogo. Quando você adiciona isso ao pom pai, todos os módulos filhos param de vê-lo . E, portanto, você é forçado a entrar em cada módulo individual que precisa e declará-lo novamente ( Child AeChild B , sem a versão).

E, obviamente, você não faz isso Child Ce, portanto, seu módulo permanece enxuto.

Andrejs
fonte
As dependências mencionadas em <dependencyManagement> serão downloded para o projeto pai pom?
Jaspreet Jolly
Você tem certeza de que, se usarmos <dependencyManagement>o pom pai, por padrão, as dependências não serão herdadas nos poms filhos? Porque no doc: maven.apache.org/guides/introduction/… ao explicar o segundo uso do <dependencyManagement>, parece que ele será herdado por padrão. Em uma linha, eles estão dizendo que: "Quando o maven é executado no projeto B, a versão 1.0 dos artefatos a, b, c e d será usada independentemente da versão especificada em seu pom", mesmo que "b" não seja usado em o projeto B
chirag soni
Experimente você mesmo
Andrejs
17

Existem algumas respostas que descrevem as diferenças entre <depedencies>e <dependencyManagement>marcam com maven.

No entanto, alguns pontos elaborados abaixo de forma concisa:

  1. <dependencyManagement>permite consolidar todas as dependências (usadas no nível filho pom) usadas em diferentes módulos - clareza , gerenciamento centralizado de versões de dependência
  2. <dependencyManagement>permite atualizar facilmente / fazer downgrade de dependências com base na necessidade; em outro cenário, isso precisa ser exercido em todos os níveis de pom filho - consistência
  3. as dependências fornecidas no <dependencies>tag são sempre importadas, enquanto as dependências fornecidas no <dependencyManagement>pai pom serão importadas apenas se o pom filho tiver a respectiva entrada em seu <dependencies>tag.
Amit Kaneria
fonte
17

Desculpe, estou muito atrasado para a festa.

Deixe-me tentar explicar a diferença usando mvn dependency:tree comando

Considere o exemplo abaixo

POM dos Pais - Meu Projeto

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

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

POM filho - módulo de aplicativo (não possui dependência extra, deixando as dependências vazias)

 <dependencies>
</dependencies>

Ao executar o mvn dependency:treecomando, obtemos o seguinte 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

A goiaba do Google é listada como dependência em todos os módulos (incluindo pai), enquanto o apache commons é listado como dependência apenas no módulo de dados (nem mesmo no módulo pai)

IamVickyAV
fonte
11

Se a dependência foi definida no elemento dependencyManagement do pom de nível superior, o projeto filho não precisou listar explicitamente a versão da dependência. se o projeto filho definisse uma versão, substituiria a versão listada na seção dependencyManagement do POM de nível superior. Ou seja, a versão dependencyManagement é usada apenas quando o filho não declara uma versão diretamente.

Mustafa Güven
fonte
1
Acredito que esta afirmação pode não estar correta. Nos exemplos de Gerenciamento de Dependência do Maven (# 2), eles dizem que as dependências definidas em um pom pai com uma versão substituem a versão especificada no pom filho: "Quando o maven é executado no projeto B versão 1.0 dos artefatos a, b, c ed serão usados ​​independentemente da versão especificada em seu pom. "
Devdanke
@devdanke Pelo menos, questões Eclipse M2e um aviso: substituindo conseguiu versão ... para ... .
GeroldBroser restabelece Monica
4

No POM pai, a principal diferença entre o <dependencies>e <dependencyManagement>é esta:

Artefatos especificados no <dependencies>seção SEMPRE serão incluídos como uma dependência do (s) módulo (s) filho (s).

Os artefatos especificados na seção serão incluídos apenas no módulo filho se também tiverem sido especificados na seção do próprio módulo filho. Por que é bom você perguntar? porque você especifica a versão e / ou escopo no pai e pode deixá-los de fora ao especificar as dependências no POM filho. Isso pode ajudá-lo a usar versões unificadas para dependências para módulos filhos, sem especificar a versão em cada módulo filho.

Yaver
fonte
4

Apenas em minhas próprias palavras, parent-projectvocê ajuda a fornecer 2 tipos de dependências:

  • dependências implícitas : todas as dependências definidas na <dependencies>seção parent-projectsão herdadas por todos oschild-projects
  • dependências explícitas : permite selecionar as dependências a serem aplicadas no seu child-projects. Assim, você usa a <dependencyManagement>seção para declarar todas as dependências que você usará nas suas diferentes child-projects. O mais importante é que, nesta seção, você defina um <version>para não precisar declará-lo novamente no seu child-project.

O <dependencyManagement>ponto de vista do meu ponto de vista (corrija-me se estiver errado) é útil, ajudando você a centralizar a versão de suas dependências. É como um tipo de recurso auxiliar.

Harry Coder
fonte
1

No Eclipse, há mais um recurso no dependencyManagement. Quando dependenciesé usado sem ele, as dependências não encontradas são observadas no arquivo pom. Se dependencyManagementfor usado, as dependências não resolvidas permanecerão despercebidas no arquivo pom e os erros aparecerão apenas nos arquivos java. (importações e tais ...)

Gangnus
fonte
1

A diferença entre os dois é melhor apresentada no que parece ser uma definição necessária e suficiente do elemento dependencyManagement disponível nos documentos do site do Maven:

dependencyManagement

"Informações de dependência padrão para projetos que herdam deste. As dependências nesta seção não são resolvidas imediatamente. Em vez disso, quando um POM derivado deste declara uma dependência descrita por groupId e artifactId correspondentes, a versão e outros valores desta seção são usados ​​para essa dependência se ainda não foram especificados ". [ https://maven.apache.org/ref/3.6.1/maven-model/maven.html ]

Deve ser lido junto com mais informações disponíveis em uma página diferente:

“..O conjunto mínimo de informações para combinar uma referência de dependência com uma seção dependencyManagement é realmente {groupId, artifactId, type, classifier}. Em muitos casos, essas dependências se referem a artefatos de jar sem classificador. Isso nos permite abreviar a identidade definida como {groupId, artifactId}, já que o padrão para o campo type é jar e o classificador padrão é nulo. ” [ https://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html ]

Portanto, todos os subelementos (escopo, exclusões etc.) de um elemento de dependência - exceto groupId, artifactId, tipo, classificador, e não apenas versão - estão disponíveis para bloqueio / padrão no ponto (e, portanto, herdados de daí em diante), você especifica a dependência dentro de um dependencyElement. Se você especificou uma dependência com os subelementos type e classifier (consulte a página da Web citada pela primeira vez para verificar todos os subelementos) como jar e not null, respectivamente, seria necessário {groupId, artifactId, classifier, type} referenciar (resolver) essa dependência em qualquer ponto de uma herança originária do elemento dependencyManagement. Caso contrário, {groupId, artifactId} seria suficiente se você não pretender substituir os padrões de classificador e tipo (jar e null, respectivamente). Portanto, o padrão é uma boa palavra-chave nessa definição; qualquer subelemento (s) (exceto groupId,

Portanto, qualquer elemento de dependência fora do dependencyManagement, seja como referência a algum elemento dependencyManagement ou como autônomo, é imediatamente resolvido (ou seja, instalado no repositório local e disponível para caminhos de classe).

rps
fonte