Różnice między dependenceManagement i zależnościami w Maven

766

Jaka jest różnica między dependencyManagementi dependencies? Widziałem dokumenty w witrynie Apache Maven. Wydaje się, że zależność zdefiniowana w parametrze dependencyManagementmoże być używana w jego modułach potomnych bez określania wersji.

Na przykład:

Projekt nadrzędny (Pro-par) definiuje zależność w ramach dependencyManagement:

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

Następnie w dziecku Pro-par mogę użyć junit:

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

Zastanawiam się jednak, czy konieczne jest zdefiniowanie junit w pom-rodzicu? Dlaczego nie zdefiniować go bezpośrednio w potrzebnym module?

hguser
źródło

Odpowiedzi:

463

Zarządzanie zależnościami pozwala skonsolidować i scentralizować zarządzanie wersjami zależności bez dodawania zależności dziedziczonych przez wszystkie elementy potomne. Jest to szczególnie przydatne, gdy masz zestaw projektów (tj. Więcej niż jeden), który dziedziczy wspólnego rodzica.

Innym niezwykle ważnym przypadkiem użycia dependencyManagementjest kontrola wersji artefaktów używanych w zależnościach przechodnich. Trudno to wyjaśnić bez przykładu. Na szczęście jest to zilustrowane w dokumentacji.

Pascal Thivent
źródło
17
Czy więc trzeba zadeklarować zależności w pom projektu potomnym, nawet jeśli zadeklarowano je w pom projektu nadrzędnym w sekcji <dependencyManagement>? Czy można dokonać pewnego rodzaju dziedziczenia zależności?
johnny-b-goode
55
Tak, nadal musisz je zdefiniować w potomnym POM, aby pokazać, że ich używasz. W rzeczywistości nie są uwzględniane w projektach potomnych tylko dlatego, że znajdują się w <dependencyManagement>macierzystej POM. Uwzględnienie zależności w <dependencyManagement>scentralizowanym zarządzaniu wersją, zakresem i wykluczeniami dla każdej zależności, jeśli i kiedy zdecydujesz się jej użyć. Przewodnik Mavena dotyczący zarządzania zależnościami zawiera wszystkie szczegóły.
hotshot309
2
Drugi akapit ( dependencyManagementtakże kontroluje zależności przechodnie) jest prawdziwy tylko wtedy, gdy zależności są jawnie ustawione: stackoverflow.com/questions/28312975/…
Robert Metzger
2
@ johnny-b-goode To, co wciąż możesz zrobić, to utworzyć nową dependenciessekcję w swoim pom pom. Zrobiliśmy to, aby wszystkie projekty potomne miały domyślnie pewne apache-commons i nie deklarowały ich przez cały czas.
рüффп
769

Modnie się spóźniłem na to pytanie, ale myślę, że warto odpowiedzieć jaśniej niż odpowiedź zaakceptowana (co jest poprawne, ale nie podkreśla faktycznej ważnej części, którą musisz wydedukować).

W macierzystej POM główna różnica między <dependencies>i <dependencyManagement>jest następująca:

Artefakty określone w <dependencies>sekcji ZAWSZE będą uwzględniane jako zależność modułów potomnych.

Artefakty określone w <dependencyManagement>sekcji zostaną uwzględnione w module potomnym tylko wtedy, gdy zostały również określone w <dependencies>sekcji samego modułu potomnego. Dlaczego dobrze pytasz? ponieważ określasz wersję i / lub zakres w rodzicu i możesz je pominąć, określając zależności w potomnym POM. Może to pomóc w użyciu zunifikowanych wersji dla zależności dla modułów potomnych, bez określania wersji w każdym module potomnym.

dcoder
źródło
1
Ale czy nie jest to również trochę narzutu, używając <dependencyManagement>over <dependencies>w katalogu głównym .pom? Dziecko pommoże być znacznie krótsze.
Janez Kuhar
18
To prawda. Użycie <dependencies> zamiast <dependencyManagement> stworzy krótsze poms dziecka. Jednak wiąże się to z pewnym kosztem - oznacza to, że te ZAWSZE zostaną określone ZAWSZE dla WSZYSTKICH modułów potomnych. Jeśli tylko NIEKTÓRE moduły potomne potrzebują pewnej zależności, to zamiast tego użycie „<dependencyManagement>” pozwoli ci wybrać, które moduły potomne będą miały tę zależność, i nadal będą nieco wydajne, ustawiając wersję zależności tylko w pomorze nadrzędnym.
dcoder
2
@JanezKuhar Ma dla mnie sens, że jeśli określisz zależność w module potomnym, zastąpi ona zależność od rodzica, ale przyznaję, że nie pamiętam. Będę musiał sprawdzić dokumenty maven dla tego, kiedy będę miał okazję. Chociaż może być łatwiej po prostu skonfigurować prosty projekt rodzic-dziecko i zweryfikować :)
dcoder
26
Dobre wyjaśnienie prostej koncepcji - dlaczego Maven wydaje się tak trudno wyjaśnić swoje własne narzędzie tak łatwo?
jimmy_terra
1
Dodam Artifacts specified in the <dependencies> section will ALWAYS be included as a dependency of the child module(s), że są one również zawarte w rodzicu. Wydaje się, że nie można ustawić zależności dla dzieci, ale nie dla rodzica.
kaduceusz
54

Dokumentacja na stronie Maven jest straszne. Zadaniem dependenceManagement jest po prostu przeniesienie definicji zależności (wersja, wykluczenia itp.) Na pompę nadrzędną, a następnie w pompach podrzędnych wystarczy wstawić groupId i artefactId. To jest to (z wyjątkiem łączenia łańcuchów nadrzędnych i tym podobnych, ale to też nie jest bardzo skomplikowane - dependenceManagement wygrywa z zależnościami na poziomie nadrzędnym - ale jeśli masz pytania na temat tego lub importu, dokumentacja Maven jest nieco lepsza).

Po przeczytaniu wszystkich śmieci „a”, „b”, „c” na stronie Maven i zdezorientowaniu się, ponownie napisałem ich przykład. Więc jeśli miałeś 2 projekty (proj1 i proj2), które mają wspólną zależność (betaShared), możesz przenieść tę zależność do pom-nadrzędnej. W tym momencie możesz także przenieść dowolne inne zależności (alfa i charlie), ale tylko jeśli ma to sens dla twojego projektu. Tak więc dla sytuacji opisanej w poprzednich zdaniach, oto rozwiązanie z dependenceManagement w pom nadrzędnym:

<!-- 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
źródło
2
Nieco tematyczne pytanie: co oznacza „pasek” typu zależności? Widziałem w przykładowym pom w dokumentacji Maven, ale nie mogłem znaleźć definicji. Zakładałem, że to literówka „wojny” lub „słoika”, ale widzę to w innych przykładach, takich jak twój.
NobodyMan
NobodyMan - jest to więc symbol zastępczy dla innego typu archiwum. Jak używanie „foo”. Lub można go użyć, jeśli ktoś stworzy niestandardowy typ z rozszerzeniem „pasek”. Istnieje wiele niejasnych typów archiwów. Jak sar, czyli archiwum usług jboss.
MattC
Twój przykład jest dość jasny i potwierdza to, co sam odkryłem z dokumentacji. Czy przesłałeś go do projektu Maven? Po przestudiowaniu twojego przykładu przygotowuję się do uproszczenia POM, który ma oba i potrzebuje tylko deklaracji zależności, ponieważ projekt, z którym jest związany, nie ma potomków.
David A. Gray
Miałem właśnie upuścić węzeł DependencyManagement, dopóki nie przyszło mi do głowy, że pozostawienie go pozwala mi ustalić minimalną wersję dla wszystkich podrzędnych POM, które pośrednio trafiają do drzewa zależności. Jako przykład, ścigając javax.cache.cache-apI, odkryłem znacznie nowszą wersję 1.0.0 (w porównaniu z 0.3.0), która równie dobrze może być używana przez cały czas.
David A. Gray
To wyjaśnienie jest trafne.
Smart Coder
45

To tak jak powiedziałeś; dependencyManagementsłuży do ściągnięcia wszystkich informacji o zależnościach do wspólnego pliku POM, co upraszcza odwołania w podrzędnym pliku POM.

Staje się przydatny, gdy masz wiele atrybutów, których nie chcesz wpisywać w ramach wielu projektów potomnych.

Wreszcie dependencyManagementmożna go użyć do zdefiniowania standardowej wersji artefaktu do użycia w wielu projektach.

Pran
źródło
4
Więc zależności nie dziedziczą? W każdym razie trzeba zadeklarować w pom dziecięcym projekcie?
johnny-b-goode
6
Tak, musisz je zadeklarować w projektach dla dzieci, ale bez określania wersji.
Pavel Vlasov
Ten scenariusz jest przydatny, gdy chcesz zarządzać wersjami w wielu projektach Java mających relacje rodzic-dziecko.
Anuj Kumar
43

Moim zdaniem jest jeszcze jedna rzecz, która nie jest wystarczająco podkreślona, ​​a mianowicie niechciane dziedzictwo .

Oto przykład przyrostowy:

W moim parentpom deklaruję :

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

Bum! Mam go w moich Child A, Child Bi Child Cmodułów:

  • Implicilty odziedziczone przez poms dzieci
  • Jedno miejsce do zarządzania
  • Nie ma potrzeby zmieniania niczego w poms dzieci
  • Wciąż mogę redelcare i nadpisywane version 18.0w sposób Child B, jeśli chcę.

Ale co, jeśli skończę nie potrzebując guawy Child C, ani w przyszłości Child Di Child Emodułów?

Nadal go odziedziczą, co jest niepożądane! Jest to tak samo jak zapach kodu Java God Object, w którym dziedziczysz pożyteczne bity z klasy i mnóstwo niechcianych rzeczy.

Tutaj <dependencyManagement>wchodzi w grę. Kiedy dodasz to do swojego pom pom, wszystkie moduły podrzędne przestają to widzieć . W ten sposób jesteś zmuszony wejść do każdego modułu, który tego potrzebuje, i zadeklarować go ponownie ( Child Ai Child Bbez wersji).

I oczywiście nie robisz tego Child C, a zatem twój moduł pozostaje szczupły.

Andrejs
źródło
Czy zależności wymienione w <dependencyManagement> zostaną zniesione dla projektu nadrzędnego pom?
Jaspreet Jolly
Czy jesteś pewien, że jeśli użyjemy <dependencyManagement>w pom pom, to domyślnie zależności nie zostaną odziedziczone w pom pom? Ponieważ w dokumencie doc: maven.apache.org/guides/introduction/… , wyjaśniając drugie użycie <dependencyManagement>, wygląda na to, że zostanie domyślnie odziedziczone. W jednym wierszu mówią: „Kiedy maven jest uruchamiany w projekcie B, wersja 1.0 artefaktów a, b, cid będzie używana niezależnie od wersji określonej w ich pom”, nawet jeśli „b” nie jest używane w projekt B
chirag soni
Wypróbuj sam
Andrejs,
17

Istnieje kilka odpowiedzi, przedstawiające różnice pomiędzy <depedencies>i <dependencyManagement>tagi z Maven.

Jednak kilka punktów omówionych poniżej w zwięzły sposób:

  1. <dependencyManagement>pozwala na konsolidację wszystkich zależności (używanych na poziomie pom pom) używanych w różnych modułach - przejrzystość , centralne zarządzanie wersjami zależności
  2. <dependencyManagement>pozwala na łatwą aktualizację / obniżenie zależności w zależności od potrzeb, w innym scenariuszu należy to wykonać na każdym poziomie pom dziecka - spójność
  3. Zależności podane w <dependencies>znaczniku są zawsze importowane, podczas gdy zależności podane <dependencyManagement>w pom pom nadrzędnym zostaną zaimportowane tylko wtedy, gdy podrzędny pom ma odpowiedni wpis w swoim <dependencies>znaczniku.
Amit Kaneria
źródło
17

Przepraszam za spóźnienie na imprezę.

Pozwól mi spróbować wyjaśnić różnicę za pomocą mvn dependency:treepolecenia

Rozważ poniższy przykład

Parent POM - Mój projekt

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

Dziecko POM - moduł danych

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

Dziecko POM - moduł aplikacji (nie ma dodatkowej zależności, więc pozostawienie zależności jest puste)

 <dependencies>
</dependencies>

Po uruchomieniu mvn dependency:treepolecenia otrzymujemy następujący wynik

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 jest wymieniony jako zależność w każdym module (w tym nadrzędnym), podczas gdy wspólny apache jest wymieniony jako zależność tylko w module danych (nawet w module nadrzędnym)

IamVickyAV
źródło
11

Jeśli zależność została zdefiniowana w elemencie zależności najwyższego poziomu pom, projekt potomny nie musiał jawnie wyświetlać wersji zależności. jeśli projekt potomny zdefiniował wersję, zastąpiłby wersję wymienioną w sekcji dependenceManagement POM najwyższego poziomu. Oznacza to, że wersja dependenceManagement jest używana tylko wtedy, gdy dziecko nie deklaruje wersji bezpośrednio.

Mustafa Güven
źródło
1
Uważam, że to stwierdzenie może być niepoprawne. W przykładach zarządzania zależnością Maven (# 2) mówią, że zależności zdefiniowane w pom pom z wersją zastąpią wersję określoną w pom pom: „Gdy maven jest uruchamiany w projekcie B wersja 1.0 artefaktów a, b, c i d będą używane niezależnie od wersji określonej w ich pom. ”
devdanke
@devdanke Przynajmniej problemy Eclipse m2e ostrzeżenie: nadrzędnych udało wersji ... do ... .
GeroldBroser przywraca Monikę
4

W macierzystej POM główna różnica między <dependencies>i <dependencyManagement>jest następująca:

Artefakty określone w <dependencies>sekcji ZAWSZE będą uwzględniane jako zależność modułów potomnych.

Artefakty określone w sekcji zostaną uwzględnione w module potomnym tylko wtedy, gdy zostały również określone w sekcji samego modułu potomnego. Dlaczego dobrze pytasz? ponieważ określasz wersję i / lub zakres w rodzicu i możesz je pominąć, określając zależności w potomnym POM. Może to pomóc w użyciu zunifikowanych wersji dla zależności dla modułów potomnych, bez określania wersji w każdym module potomnym.

Yaver
źródło
4

Według moich słów, parent-projectpomagasz zapewnić 2 rodzaje zależności:

  • ukryte zależności : wszystkie zależności zdefiniowane w <dependencies>sekcji w tobie parent-projectsą dziedziczone przez wszystkiechild-projects
  • wyraźne zależności : pozwala wybrać zależności, które mają zostać zastosowane w twoim child-projects. Tak więc używasz <dependencyManagement>sekcji, aby zadeklarować wszystkie zależności, których zamierzasz użyć w swojej innej child-projects. Najważniejsze jest to, że w tej sekcji definiujesz a <version>, abyś nie musiał deklarować tego ponownie w swoim child-project.

Z <dependencyManagement>mojego punktu widzenia (popraw mnie, jeśli się mylę) jest po prostu przydatny, pomagając w scentralizowaniu wersji swoich zależności. To jest coś w rodzaju funkcji pomocnika.

Harry Coder
źródło
1

W Eclipse jest jeszcze jedna funkcja dependencyManagement. Kiedy dependenciesjest używane bez niego, nieuzasadnione zależności są zauważane w pliku pom. Jeśli dependencyManagementjest używany, nierozwiązane zależności pozostają niezauważone w pliku pom, a błędy pojawiają się tylko w plikach Java. (import i takie ...)

Gangnus
źródło
1

Różnicę między tymi dwoma najlepiej najlepiej przedstawić w niezbędnej i wystarczającej definicji elementu dependenceManagement dostępnego w dokumentach witryny Maven:

dependencyManagement

„Domyślne informacje o zależnościach dla projektów, które dziedziczą z tego. Zależności w tej sekcji nie są natychmiast usuwane. Zamiast tego, gdy POM pochodzący z tej deklaruje zależność opisaną przez pasujące groupId i artefactId, wersję i inne wartości z tej sekcji są używane dla tej zależności, jeśli nie zostały jeszcze określone. ” [ https://maven.apache.org/ref/3.6.1/maven-model/maven.html ]

Należy go przeczytać wraz z dodatkowymi informacjami dostępnymi na innej stronie:

„... minimalny zestaw informacji do dopasowania odwołania do zależności do sekcji dependenceManagement to tak naprawdę {groupId, artefactId, typ, klasyfikator}. W wielu przypadkach te zależności będą odnosić się do artefaktów jar bez klasyfikatora. To pozwala nam skrócić zestaw tożsamości na {groupId, artefactId}, ponieważ domyślnym polem typu jest jar, a domyślnym klasyfikatorem jest null. ” [ https://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html ]

Tak więc wszystkie podelementy (zakres, wykluczenia itp.) Elementu zależności - inne niż groupId, artefactId, typ, klasyfikator, a nie tylko wersja - są dostępne do zablokowania / domyślnego w punkcie (a więc dziedziczone z od tego momentu) określasz zależność w ramach elementu dependenceElement. Jeśli określisz zależność z podelementami typu i klasyfikatora (zobacz pierwszą cytowaną stronę internetową, aby sprawdzić wszystkie podelementy) jako nie jar i odpowiednio null, potrzebujesz {groupId, artefactId, klasyfikator, typ} odwoływać się (rozwiązywać) tę zależność w dowolnym momencie spadku pochodzącego z elementu dependenceManagement. W przeciwnym razie wystarczy {groupId, artefactId}, jeśli nie zamierzasz zastępować wartości domyślnych dla klasyfikatora i typu (odpowiednio jar i null). Domyślne jest więc dobrym słowem kluczowym w tej definicji; dowolny podelement (-y) (inny niż groupId,

Tak więc każdy element zależności spoza dependenceManagement, czy to jako odwołanie do jakiegoś elementu dependenceManagement, czy jako samodzielny, jest natychmiast rozstrzygany (tj. Instalowany w lokalnym repozytorium i dostępny dla ścieżek klas).

rps
źródło