Maven: Abhängigkeiten verwalten


Flattr this
Endlich habe ich beim Schmökern einen Artikel über das Dependency Management von Maven gefunden. Die Quellenbeschreibung habe ich abgelegt unter:

http://www.bibsonomy.org/bibtex/2ef10bb1bc1be7806bc3fba53417bbd5f/funthomas424242

Abhängigkeiten werden in Maven bekanntlich in der pom.xml im <dependencies/> Block, ähnlich dem folgenden Beispiel definiert:

<dependencies>
    <dependency>
        <groupId>commons-logging</groupId>
        <artifactId>commons-logging</artifactId>
        <version>1.1</version>
    </dependency>
</dependencies>

Hierbei bedeutet der obige Kodeausschnitt eine Abhängigkeit zur commons-logging Bibliothek von Apache in der Version 1.1.  Die Angabe im Version Tag stellt allerdings nur eine Empfehlung an Maven dar. Falls diese Version also nicht verfügbar ist oder mit einer anderen Version kollidiert kann Maven durchaus selbst entscheiden welche Version benutzt wird.

Warum ist das überhaupt entscheidend? Ganz einfach! Wenn unser Programm von mehreren Bibliotheken abhängig ist. Wenn dabei mindestens 2 Bibliotheken von einer commons-logging Implementierung abhängig sind. Dann wäre es verdammt gut wenn die beiden Bibliotheken von der selben Version der commons-logging Implementierung abhängen. Falls das nicht so ist, müssten wir mehrere Versionen der commons-logging Bibliothek mit unserem Programm ausliefern. Damit ist aber nicht gesagt, dass dies dann auch läuft. Letztlich wird die Bibliothek angezogen welche zuerst im Klassenpfad liegt. Nicht gefundene Methoden und andere Fehler können die Folge sein.

Hier setzt das Dependency Management von Maven an. Maven prüft die Abhängigkeiten auf genau solche Konflikte und löst diese dann nach vorgegebenen Regeln auf. Beim Berechnen der zu benutzenden Versionen spielen mindestens folgende Dinge eine Rolle:

  • Angabe der Version im Version Tag:
    • <version>[1.1] </version>exakte Versionsangabe
      -> nur diese darf verwendet werden.
    • <version>1.1</version> empfohlene Versionsangabe
      -> Maven sollte diese benutzen, muss es aber nicht.
  • Scope der Abhängigkeit
    (compile, provided, test, runtime, system, import)
  • Angaben im Dependency Management des Haupt- oder des Eltern- Projektes.
  • Entfernung der Abhängigkeit (Dependency mediation)
    Wenn Projekt A abhängt von B und C und weiterhin B abhängt von D sowie D abhängt von E in Version 2 und C abhängt von E in Version 1 dann wird Version 1 von E benutzt. Weil die Entfernung in der transitiven Hülle von E (Version 1) über C zum Main Projekt A kürzer ist als die Entfernung von E (Version 2) über D und B zu A.
  • Scope der transitiven Abhängigkeit  (Dependency scope)
    Der Scope der transitiven Abhängigkeiten wird von Maven für die Berechnung nach definierten Regeln modifiziert (siehe Tabelle 1).

Wer wissen möchte welche Abhängigkeiten bestehen, kann sich den Graphen per Shell Kommando erzeugen lassen:

mvn dependency:tree

Die Ausgabe des Baumes auf der Console sieht beispielsweise für das jar-install-plugin wie folgt aus:

[INFO]
[INFO] --- maven-dependency-plugin:2.1:tree (default-cli) @ jar-install-plugin ---
[INFO] net.sf.maven.plugins:jar-install-plugin:maven-plugin:0.1-SNAPSHOT
[INFO] +- junit:junit:jar:4.4:test (scope not updated to compile)
[INFO] +- commons-io:commons-io:jar:1.4:compile
[INFO] +- org.apache.maven:maven-plugin-api:jar:2.0.9:compile
[INFO] +- org.apache.maven:maven-artifact:jar:2.0.9:compile
[INFO] |  \- org.codehaus.plexus:plexus-utils:jar:1.5.1:compile
[INFO] +- org.apache.maven:maven-project:jar:2.0.9:compile
[INFO] |  +- org.apache.maven:maven-settings:jar:2.0.9:compile
[INFO] |  +- org.apache.maven:maven-profile:jar:2.0.9:compile
[INFO] |  +- org.apache.maven:maven-artifact-manager:jar:2.0.9:compile
[INFO] |  |  +- org.apache.maven:maven-repository-metadata:jar:2.0.9:compile
[INFO] |  |  \- org.apache.maven.wagon:wagon-provider-api:jar:1.0-beta-2:compile
[INFO] |  +- org.apache.maven:maven-plugin-registry:jar:2.0.9:compile
[INFO] |  \- org.codehaus.plexus:plexus-container-default:jar:1.0-alpha-9-stable-1:compile
[INFO] |     \- classworlds:classworlds:jar:1.1-alpha-2:compile
[INFO] \- org.apache.maven:maven-model:jar:2.0.9:compile

Um die verwendeten Versionen über die gesamte transitive Hülle der Abhängigkeiten steuern zu können, sollte hierzu die Beschreibung über die Tags <dependencyManagement/> erfolgen. Die zwischen den Tag’s definierten Versionen der Bibliotheken und Projekte werden dann von Maven auch bei der Auflösung von Konflikten in 3th Party Bibliotheken benutzt. Dazu folgendes Kodebeispiel:

<dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>commons-logging</groupId>
      <artifactId>commons-logging</artifactId>
      <version>1.1</version>
    </dependency>
  </dependencies>
</dependencyManagement>
<dependencyManagement> <dependencies> <dependency> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> <version>1.1</version> </dependency> </dependencies> </dependencyManagement>

Durch diese Deklaration wird Maven angehalten alle Abhängigkeiten so zu wählen, dass die commons-logging Bibliothek in der Version 1.1 benutzt werden kann. Wie bereits erwähnt es ist eine Empfehlung an Maven die nicht eingehalten werden muss. Daher macht es immer Sinn abschließend die tatsächlich benutzten Versionen über mvn dependency:tree zu prüfen.

Tabelle 1

Einbindung der Wirt-Lib im
aktuellen Projekt POM mit Scope
Scope in der
eingebundenen Lib
Geänderter Scope
compile compile compile
compile runtime runtime
provided compile, runtime provided
test compile, runtime test
runtime compile, runtime runtime
system * – (entfernt)
import n/a n/a
* test – (entfernt)
* provided – (entfernt)
* system – (entfernt)

(Wenn jemand zu dieser Tabelle eine bessere Erläuterung als oben oder im nachfolgende Link hat, bitte als Kommentar an diesen Artikel anfügen – vielen Dank)

Weiterführende Links:

Post a comment or leave a trackback: Trackback URL.

Schreibe einen Kommentar

Trage deine Daten unten ein oder klicke ein Icon um dich einzuloggen:

WordPress.com-Logo

Du kommentierst mit Deinem WordPress.com-Konto. Abmelden / Ändern )

Twitter-Bild

Du kommentierst mit Deinem Twitter-Konto. Abmelden / Ändern )

Facebook-Foto

Du kommentierst mit Deinem Facebook-Konto. Abmelden / Ändern )

Google+ Foto

Du kommentierst mit Deinem Google+-Konto. Abmelden / Ändern )

Verbinde mit %s

%d Bloggern gefällt das: