Maven-Abhängigkeitsauflösung (Konflikt)

78

Angenommen, ich habe vier Projekte:

  • Projekt A (abhängig von B und D)
  • Projekt B (hat eine Abhängigkeit von D)
  • Projekt C (abhängig von D)
  • Projekt D.

Wenn ich in diesem Szenario Projekt A ausführe, löst Maven die Abhängigkeit von D korrekt auf. Wenn ich dies richtig verstehe, nimmt Maven die Abhängigkeit immer mit dem kürzesten Pfad. Da D eine direkte Abhängigkeit von A ist, wird eher das D verwendet, das in B angegeben ist.

Nehmen wir nun diese Struktur an:

  • Projekt A (abhängig von B und C)
  • Projekt B (hat eine Abhängigkeit von D)
  • Projekt C (abhängig von D)
  • Projekt D.

In diesem Fall haben die Pfade zum Auflösen von D die gleiche Tiefe. Was passiert ist, dass Maven einen Konflikt haben wird. Ich weiß, dass es möglich ist, Maven zu sagen, dass er Abhängigkeiten ausschließen sollte. Aber meine Frage ist, wie man solche Probleme angeht. Ich meine, in einer realen Anwendung haben Sie viele Abhängigkeiten und möglicherweise auch viele Konflikte.

Ist die Best-Practice-Lösung wirklich, um Dinge auszuschließen, oder gibt es andere mögliche Lösungen dafür? Ich finde es sehr schwierig, damit umzugehen, wenn ich plötzlich eine ClassNotFound-Ausnahme bekomme, weil sich einige Versionen geändert haben, was dazu führte, dass Maven eine andere Abhängigkeit annahm. Wenn Sie diese Tatsache kennen, können Sie natürlich leichter erraten, dass es sich bei dem Problem um einen Abhängigkeitskonflikt handelt.

Ich benutze Maven 2.1-SNAPSHOT.

Kukudas
quelle
2
Ich denke, Sie sollten keine 2.1-SNAPSHOT-Version verwenden, die eine DEV-Version ist. Maven 2 ist in Version 2.2.1 final verfügbar.
Riff
4
Übrigens, Maven 3.x ist seit einiger Zeit stabil und viel schneller und zuverlässiger als Maven 2.x
Sean Patrick Floyd
3
Diamanten sind der schlimmste Feind eines Programmierers ...
Tony Lâmpada
@ Sean Patrick Floyd alle Maven-Version sind stabiler als SNAPSHOT :)
MariuszS

Antworten:

88

Die Maven-Methode zum Lösen solcher Situationen besteht darin, einen <dependencyManagement>Abschnitt in das Stammfenster Ihres Projekts aufzunehmen, in dem Sie angeben, welche Version welcher Bibliothek verwendet werden soll.

BEARBEITEN:

<dependencyManagement>
  <dependencies>
    <dependency>
        <groupId>foo</groupId>
        <artifactId>bar</artifactId>
        <version>1.2.3</version>
    </dependency>
   </dependencies>
</dependencyManagement>

Unabhängig davon, welche Version der Bibliothek foo: bar von einer Abhängigkeit angefordert wird, wird für dieses Projekt und alle Unterprojekte immer Version 1.2.3 verwendet.

Referenz:

Sean Patrick Floyd
quelle
Was ist, wenn die Version von Projekt D abweicht? Projekt B (abhängig von D1.0) - Kann nicht mit D2.0 arbeiten Projekt C (abhängig von D2.0) - Kann nicht mit D1.0 arbeiten
Nitul
2
@ Nitul dann bist du im Grunde geschraubt. Ihre einzige Möglichkeit ist dann, eine der Abhängigkeiten mit etwas wie dem Maven Shade Plugin neu zu packen
Sean Patrick Floyd
4
Zur Verdeutlichung dependencyManagementgelten die in angegebenen Versionsnummern für transitive Abhängigkeiten und Projektabhängigkeiten ohne explizite Version. Projektabhängigkeiten mit einer expliziten Version überschreiben jedoch die Version im dependencyManagementAbschnitt.
pnewhook
31

Maven kann beide Situationen ohne Konflikte bewältigen. Konflikte bestehen, wenn zwei Versionen einer transitiven Abhängigkeit erforderlich sind. Die ClassNotFoundExceptionSie beschreiben , ergibt sich aus der App (oder einer Abhängigkeit) versucht , eine Klasse zu verwenden , nicht verfügbar in der Version der Konflikt Abhängigkeit, wird tatsächlich verwendet wird . Es gibt mehrere Möglichkeiten, das Problem zu beheben.

  1. Aktualisieren Sie die Versionen der Bibliotheken, die Sie verwenden und die von der Konfliktabhängigkeit abhängen, so dass sie alle von derselben Versionsversion dieser Abhängigkeit abhängen
  2. Deklarieren Sie die Konfliktabhängigkeit als direkte Abhängigkeit Ihres Projekts von der Version, die Sie einschließen möchten (im Beispiel die mit der fehlenden Klasse).
  3. Geben Sie über den <dependencyManagement>Abschnitt des POM an, welche Version der Konfliktabhängigkeit transitive Abhängigkeiten verwenden sollen
  4. Schließen Sie die unerwünschten Versionen der in Konflikt stehenden Abhängigkeit explizit von der Aufnahme in die Abhängigkeiten aus, die von ihnen abhängig sind, indem Sie eine <exclusion>
Daniel
quelle
21

Dies ist im Grunde kein Maven-Problem, sondern ein Java-Problem. Wenn Projekt B und Projekt C zwei inkompatible Versionen von Projekt D benötigen, können Sie beide nicht in Projekt A verwenden.

Wie Sie bereits wissen, besteht die Maven-Methode zur Lösung solcher Konflikte leider darin, auszuwählen, welche ausgeschlossen werden sollen.

Verwenden mvn dependency:analyzeund mvn dependency:treehilft bei der Suche nach Konflikten.

Buhb
quelle
+1. Ich würde sogar sagen, dass Artefakte, die nicht abwärtskompatibel sind, ihre Gruppen-ID und / oder Artefakt-ID ändern sollten.
Sean Patrick Floyd
Ja, aber das dauert nur die Hälfte. Die Artefakte dürfen keine Klassen mit demselben Paket und Namen enthalten.
Buhb
Ja, leider. In diesem Fall benötigen Sie ProGuard oder das Maven Shade Plugin
Sean Patrick Floyd
Würde OSGI dieses hypothetische Szenario lösen? (Um nicht vorzuschlagen, dass dies eine einfache Lösung ist - fragen Sie einfach.)
Jhericks
Möglicherweise. Ich kenne OSGI nicht gut genug, um mit Sicherheit etwas zu sagen.
Buhb
18

Mit der Regel Abhängigkeitskonvergenz können Sie konsistente Abhängigkeiten im gesamten Projekt erzwingen .

 <plugin>
     <groupId>org.apache.maven.plugins</groupId>
     <artifactId>maven-enforcer-plugin</artifactId>
     <version>1.3.1</version>
     <executions>
        <execution>
           <id>enforce</id>
           <configuration>
              <rules>
                 <DependencyConvergence/>
              </rules>
           </configuration>
           <goals>
              <goal>enforce</goal>
           </goals>
        </execution>
     </executions>
  </plugin>
MariuszS
quelle
9

Eine mögliche Strategie besteht darin, für das Hauptprojekt anzugeben, welche Version von D verwendet werden soll (die neueste fg). Wenn Bibliothek D jedoch nicht abwärtskompatibel ist, haben Sie ein Problem, wie von kukudas angegeben - es ist unmöglich, beide Bibliotheken in Ihrem Projekt zu verwenden.

In einer solchen Situation kann es erforderlich sein, in älteren Versionen entweder B oder C zu verwenden, sodass beide von kompatiblen Versionen von D abhängen.

Stepan Vihor
quelle