Вирішення залежностей Maven (конфлікт)


78

Скажімо, у мене є чотири проекти:

  • Проект A (має залежність від B і D)
  • Проект B (має залежність від D)
  • Проект C (має залежність від D)
  • Проект D

У цьому випадку, якщо я запускаю проект A, Maven правильно вирішить залежність до D. Якщо я це правильно розумію, Maven завжди приймає залежність із найкоротшим шляхом. Оскільки D - пряма залежність від A, вона буде використовуватися швидше, ніж D, яка вказана в межах B.

А тепер припустимо таку структуру:

  • Проект A (має залежність від B і C)
  • Проект B (має залежність від D)
  • Проект C (має залежність від D)
  • Проект D

У цьому випадку шляхи до вирішення D мають однакову глибину. Що трапляється, що у Мейвен буде конфлікт. Я знаю, що можна сказати Мейвену, що він повинен виключити залежності. Але моє питання полягає в тому, як вирішити такі проблеми. Я маю на увазі, що в реальному світі у вас багато залежностей і, можливо, багато конфліктів.

Чи справді найкращим практичним рішенням є виключення матеріалів чи існують інші можливі рішення для цього? Мені дуже важко мати справу, коли я раптом отримую виняток ClassNotFound, оскільки деякі версії змінилися, що змусило Maven взяти іншу залежність. Звичайно, знаючи цей факт, трохи легше здогадатися, що проблема полягає в конфлікті залежностей.

Я використовую maven 2.1-SNAPSHOT.


2
Я думаю, ви не повинні використовувати версію 2.1-SNAPSHOT, яка є версією DEV. Maven 2 доступний у версії 2.2.1 final.
риф

4
До речі, Maven 3.x деякий час стабільний і набагато швидший та надійніший, ніж maven 2.x
Шон Патрік Флойд

3
Діаманти - найлютіший ворог програміста ...
Тоні Лампада,

@ Sean Patrick Floyd всі версії maven стабільніші за SNAPSHOT :)
MariuszS

Відповіді:


88

Основний спосіб вирішення подібних ситуацій полягає у включенні <dependencyManagement>розділу в кореневу пам'ять вашого проекту, де ви вказуєте, яка версія якої бібліотеки буде використана.

РЕДАГУВАТИ:

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

Тепер незалежно від того, яку версію бібліотеки foo: bar запитує залежність, для цього проекту та всіх підпроектів завжди буде використана версія 1.2.3.

Довідково:


Що робити, якщо версія відрізняється від проекту D, проект B (має залежність від D1.0) - Не може працювати з D2.0 Проект C (має залежність від D2.0) - Не може працювати з D1.0
Nitul

2
@Nitul, то ти в основному скручений. Тоді ваш єдиний варіант - перепакувати одну із залежностей, використовуючи щось на зразок плагіна maven shadow
Шон Патрік Флойд

4
Для уточнення, номери версій, зазначені в, dependencyManagementзастосовуються до перехідних залежностей та залежностей проекту без явної версії. Але залежності проекту з явною версією замінюють версію в dependencyManagementрозділі.
pnewhook

31

Maven може впоратися з обома ситуаціями без будь-яких конфліктів. Конфлікти будуть існувати, коли потрібні дві версії транзитивної залежності. ClassNotFoundExceptionВи охарактеризували результати з програми (або залежності) намагається використовувати клас не доступний у версії конфліктної залежності , яка на самому ділі звикає. Існує кілька способів вирішити проблему.

  1. Оновіть версії використовуваних вами бібліотек, які залежать від конфліктної залежності, так що всі вони залежать від однієї версії цієї залежності
  2. Оголосіть конфліктну залежність як пряму залежність вашого проекту з версією, яку ви хочете включити (у прикладі, ту, що містить відсутній клас)
  3. Вкажіть, яку версію конфліктної залежності використовувати транзитивні залежності, за допомогою <dependencyManagement>розділу POM
  4. Явно виключіть небажані версії конфліктної залежності від включення до залежностей, які покладаються на них за допомогою <exclusion>

22

Це принципово не проблема maven, а проблема Java. Якщо Project B і Project C потребують двох несумісних версій проекту D, то ви не можете використовувати їх обидві в Project A.

Спосіб вирішення подібних конфліктів Мейвен, на жаль, як ви вже знаєте, вибрати, які з них виключити.

Використання mvn dependency:analyzeта mvn dependency:treeдопомога у виявленні конфліктів.


+1. Я піду так далеко, що скажу, що артефакти, які не є зворотно сумісними, повинні змінити їх groupId та / або artifactId.
Шон Патрік Флойд,

Так, але це займає лише половину шляху. Артефакти не повинні містити класи з однаковим пакетом та назвою.
Бух

Так, на жаль. У цьому випадку вам знадобиться ProGuard або плагін Maven Shade
Шон Патрік Флойд

Чи вирішить OSGI цей гіпотетичний сценарій? (Щоб не припускати, що це просте рішення - просто запитати.)
jhericks

Можливо. Я не знаю OSGI настільки гарний, щоб сказати що-небудь напевно.
Бух

18

Ви можете застосувати послідовні залежності в цілому проекті за допомогою правила збіжності залежностей .

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

9

Однією з можливих стратегій є визначення для основного проекту, яку версію D використовувати (найновішу fg). Однак, якщо бібліотека D не сумісна із зворотною функцією, у вас виникла проблема, як зазначив kukudas - неможливо використовувати обидві бібліотеки у своєму проекті.

У такій ситуації може знадобитися використовувати B або C у старшій версії, щоб обидва залежали від сумісних версій D.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.