Maven – kolejność rozwiązywania tranzytywnych zależności

Jeśli nie określimy żadnej wersji dla zależności tranzytywnych, to Maven spróbuje sam wybrać odpowiednią wersję. I ogólna zasada to – wygrywa zależność będąca najbliżej. Czyli będą najbliżej w pionie jak i w poziomie.

Zakładając następującą strukturę projektu

Załóżmy dla potrzeb następnych akapitów następującą strukturę projektu:

D1 -> D12 -> DT(version 1)
D2 -> DT(version 2)
D3 -> DT(version 3)
D4 -> DT(version 2)

Gdzie D1,D2… są to po prostu zależności. A zależność, którą Maven będzie próbował rozwiązać to DT (w nawiasach podane są wersje). Strzałki (->) oznaczają po prostu zależność w tym samym kierunku co ich groty (od artefaktu po lewej do artefaktu po prawej).

Najbliżej w pionie

Jeśli chodzi o sytuację kolejności w pionie to sprawa jest prosta – wygrywa ta, która jest zdefiniowana jako pierwsza (patrząc od góry do dołu). Czyli w naszym projekcie, gdyby Maven brał pod uwagę tylko i wyłącznie zasadę „Najbliżej w pionie”, to wygrała by wersja version 1:

D1 -> D12 -> DT(version 1)
D2 -> DT(version 2)
D3 -> DT(version 3)
D4 -> DT(version 2)

Najbliżej w poziomie

Jeśli zaś chodzi o najbliższą zależność w poziomie, to wygrywa ta zależność, która będzie miała najkrótszy ciąg zależności. Jeśli Maven brałby pod uwagę tylko zasadę „Najbliżej w poziomie” to byśmy mieli trzech kandydatów:

D1 -> D12 -> DT(version 1)
D2 -> DT(version 2)
D3 -> DT(version 3)
D4 -> DT(version 2)

Najbliżej w pionie i najbliżej poziomie

Biorąc pod uwagę obydwie zasady – „Najbliżej w pionie” i „Najbliżej w poziomie”, Maven wybierze zależność z wersją version 2:

D1 -> D12 -> DT(version 1)
D2 -> DT(version 2)
D3 -> DT(version 3)
D4 -> DT(version 2)

I to jest zasada, którą kieruje się Maven przy rozwiązywaniu konfliktów.

Maven dependency tree

Aby zobaczyć jak Maven rozwiązuje tranzytywne konflikty wersji, można użyć wtyczki dependency z komendą tree i parametrem verbose:

mvn dependency:tree -Dverbose

Dla zbliżonej struktury jak w założeniach (patrz pierwszy nagłówek), Maven zwraca następujące drzewo zależności:

[INFO] pl.damianradowiecki:TEST:jar:1.0-SNAPSHOT
[INFO] +- pl.damianradowiecki:D1:pom:1:compile
[INFO] |  \- pl.damianradowiecki:D12:pom:1:compile
[INFO] |     \- (pl.damianradowiecki:DT:jar:1:compile - omitted for conflict with 2)
[INFO] +- pl.damianradowiecki:D2:pom:1:compile
[INFO] |  \- pl.damianradowiecki:DT:jar:2:compile
[INFO] +- pl.damianradowiecki:D3:pom:1:compile
[INFO] |  \- (pl.damianradowiecki:DT:jar:3:compile - omitted for conflict with 2)
[INFO] \- pl.damianradowiecki:D4:pom:1:compile
[INFO]    \- (pl.damianradowiecki:DT:jar:2:compile - omitted for duplicate)

Jak można zauważyć, niektóre zależności są oznaczane jako omitted for conflict a inne jako omitted for duplicate.

omitted for conflict

Maven w drzewie zależności oznacza zależności jako omitted for conflict, te zależności które przegrały w „wyścigu” (najbliżej w pionie i najbliżej w poziomie) i mają różną wersję od tej wybranej.

omitted for duplicate

Maven w drzewie zależności oznacza zależności jako omitted for duplicate, te zależności które przegrały w „wyścigu” (najbliżej w pionie i najbliżej w poziomie) i mają tę samą wersję co wybrana.

Warto zajrzeć

1. Projekt odzwierciedlający przykład z wpisu (w celu uruchomienia podążaj za instrukcjami w pliku VersionTest.java)
2. https://maven.apache.org/plugins-archives/maven-dependency-plugin-2.8/examples/resolving-conflicts-using-the-dependency-tree.html
3. https://reflectoring.io/maven-bom/

Pozostaw komentarz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *