Чи все-таки слід виключити артефакти, успадковані від батьківського POM?


119

Артефакти із залежностей можна виключити, оголосивши <exclusions>елемент всередині A, <dependency>але в цьому випадку потрібно виключити артефакт, успадкований від батьківського проекту. Витяг обговорюваної УОЗ наступний:

<project>
  <modelVersion>4.0.0</modelVersion>
  <groupId>test</groupId>
  <artifactId>jruby</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <parent>
        <artifactId>base</artifactId>
        <groupId>es.uniovi.innova</groupId>
        <version>1.0.0</version>
    </parent>

    <dependencies>      
        <dependency>
            <groupId>com.liferay.portal</groupId>
            <artifactId>ALL-DEPS</artifactId>
            <version>1.0</version>
            <scope>provided</scope>
            <type>pom</type>
        </dependency>
    </dependencies>
</project>

baseартефакт, залежить javax.mail:mail-1.4.jarі ALL-DEPSзалежить від іншої версії тієї ж бібліотеки. Через те, що mail.jarз ALL-DEPSіснування в середовищі виконання, хоча і не експортується, стикається з тим, mail.jarщо існує у материнській родині, яка визначається як compile.

Рішенням може бути позбавлення mail.jar від батьківського POM, але більшість проектів, які успадковують базу, потребують цього (як це перехідна залежність для log4j). Тож, що я хотів би зробити, це просто виключити батьківську бібліотеку з дочірнього проекту , як це можна зробити, якби baseзалежність, а не батьківська пом:

...
    <dependency>
        <artifactId>base</artifactId>
        <groupId>es.uniovi.innova</groupId>
        <version>1.0.0</version>
        <type>pom<type>
        <exclusions>
          <exclusion>
             <groupId>javax.mail</groupId>
             <artifactId>mail</artifactId>
          </exclusion>
        </exclusions>
    </dependency>
...

Відповіді:


49

Деякі ідеї:

  1. Можливо, ви могли б просто не успадкувати від батьків у такому випадку (і оголосити залежність baseіз виключенням). Не зручно, якщо у батьківській пам’яті багато речей.

  2. Інша справа , щоб тест був би оголосити mailартефакт з версією , необхідної ALL-DEPSпід dependencyManagementв батьківському ПОМ , щоб змусити конвергенцію (хоча я не впевнений , що це дозволить вирішити проблему рамковий).

<dependencyManagement>
  <dependencies>
    <dependency>    
      <groupId>javax.mail</groupId>
      <artifactId>mail</artifactId>
      <version>???</version><!-- put the "right" version here -->
    </dependency>
  </dependencies>
</dependencyManagement>
  1. Або ви можете виключити mailзалежність від log4j, якщо ви не використовуєте функції, що покладаються на неї (і це я б робив):
<dependency>
  <groupId>log4j</groupId>
  <artifactId>log4j</artifactId>
  <version>1.2.15</version>
  <scope>provided</scope>
  <exclusions>
    <exclusion>
      <groupId>javax.mail</groupId>
      <artifactId>mail</artifactId>
    </exclusion>
    <exclusion>
      <groupId>javax.jms</groupId>
      <artifactId>jms</artifactId>
    </exclusion>
    <exclusion>
      <groupId>com.sun.jdmk</groupId>
      <artifactId>jmxtools</artifactId>
    </exclusion>
    <exclusion>
      <groupId>com.sun.jmx</groupId>
      <artifactId>jmxri</artifactId>
    </exclusion>
  </exclusions>
</dependency>
  1. Або ви можете повернутися до версії 1.2.14 log4j замість єретичної версії 1.2.15 (чому вони не позначили вищезазначені залежності як необов'язкові ?!).

Спасибі за Вашу відповідь. Він містить багато корисної інформації. Щодо 1) Як ви вже помітили, це не буде оптимальним, оскільки батьківський пом не містить лише залежностей, які транзитивно будуть вирішені, якщо база була позначена як залежність, але також загальні звіти, управління джерелами та інші речі, що повторно використовуються серед кожного проекту в компанії. По відношенню до 2) я спробував це, але також вказав об'єм артефакту як передбачений, і він працював :). Спочатку я подумав, що компіляція має перевагу над наданою, вона не спрацює, але, на щастя, я помилився (дитина POM переосмислює конфігурацію батьків)
Мігель

29

Ви можете згрупувати свої залежності в іншому проекті за допомогою упаковки, pomяк описано в найкращих практиках Sonatypes :

<project>
    <modelVersion>4.0.0</modelVersion>
    <artifactId>base-dependencies</artifactId>
    <groupId>es.uniovi.innova</groupId>
    <version>1.0.0</version>
    <packaging>pom</packaging>
    <dependencies>
        <dependency>
            <groupId>javax.mail</groupId>
            <artifactId>mail</artifactId>
            <version>1.4</version>
        </dependency>
    </dependencies>
</project>

і посилайтеся на них з батьків-пом (дивіться залежність <type>pom</type>):

<project>
    <modelVersion>4.0.0</modelVersion>
    <artifactId>base</artifactId>
    <groupId>es.uniovi.innova</groupId>
    <version>1.0.0</version>
    <packaging>pom</packaging>
    <dependencies>
        <dependency>
            <artifactId>base-dependencies</artifactId>
            <groupId>es.uniovi.innova</groupId>
            <version>1.0.0</version>
            <type>pom</type>
        </dependency>
    </dependencies>
</project>

Ваш дочірній проект успадковує цей батьківський пом, як і раніше. Але тепер залежність від пошти може бути виключена в дочірньому проекті в рамках dependencyManagementблоку:

<project>
    <modelVersion>4.0.0</modelVersion>
    <groupId>test</groupId>
    <artifactId>jruby</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <parent>
        <artifactId>base</artifactId>
        <groupId>es.uniovi.innova</groupId>
        <version>1.0.0</version>
    </parent>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <artifactId>base-dependencies</artifactId>
                <groupId>es.uniovi.innova</groupId>
                <version>1.0.0</version>
                <exclusions>
                    <exclusion>
                        <groupId>javax.mail</groupId>
                        <artifactId>mail</artifactId>
                    </exclusion>
                </exclusions>
            </dependency>
        </dependencies>
    </dependencyManagement>
</project>

4
+1 для цього, хоча дочірній пом повинен використовувати розділ <dependitions>, а не <dependencyManagement>, оскільки останній призначений для управління версіями залежностей з батьківського pom.
Меттью Мудрий

1
Це також відоме як BOM, він же законопроект матеріалів :-)
Pim Hazebroek

Це працює лише з перехідними залежностями? Мій батьківський pom містить log4j, і це заважає нормально працювати в моєму каналі.
Шрідхар Сарнобат

10

Не використовуйте батьківський пом

Це може здатися екстремальним, але той самий спосіб "пекло спадщини" є причиною, коли люди повертаються спиною об'єктно-орієнтованому програмуванню (або віддають перевагу композиції над спадщиною ), видаляють проблемний <parent>блок і копіюють та вставляють все, <dependencies>що потрібно (якщо ваша команда дає вам ця свобода).

Припущення про те, що розщеплення дітей на батьків та дитини для «повторного використання» та «уникнення надмірності» слід ігнорувати, і ви повинні спочатку обслуговувати свої негайні потреби (вилікування є найгіршим, ніж захворювання). Крім того, надмірність має свої переваги, а саме - незалежність від зовнішніх змін (тобто стабільності).

Це простіше, ніж це звучить, якщо ви генеруєте ефективний пом (eclipse забезпечує це, але ви можете генерувати його з командного рядка за допомогою mvn help:effective).

Приклад

Я хочу використовувати logbackяк мою прив'язку slf4j, але мій батьківський пом включає log4jзалежність. Я не хочу йти і мушу підштовхувати залежність інших дітей від log4j вниз до власних pom.xmlфайлів, щоб моє було безперешкодно.


1
Задокументуйте це (і процедуру, яку ви дотримувались) дуже обережно, оскільки майбутнім обслуговуючим особам потрібно повторити це, якщо потрібно використовувати оновлену версію батьківського пам’яті.
Thorbjørn Ravn Andersen

Звичайно, ти маєш на увазі, що не використовуєш залежність у батьківських пом? Батьківський пом все ще дуже корисний для управління версіями залежностей та загальними плагінами. Просто використання його для введення залежності може призвести до відмови - ми використовуємо його лише для обов'язкових залежностей (як набір необхідних початкових джерел завантаження для батьків для мікросервісів)
Аміт Гольдштейн

Ні, я не кажу, що використовуйте легкий батьківський пом. Інші члени вашої команди не дозволять вам обрізати батьківський пом, оскільки інші додатки залежать від мотлоху в батьківській пом, який ви не хочете.
Шрідхар Сарнобат

8

Перевизначте залежність (у дитячій пом.) scopeСистемою, що вказує на порожню банку:

<dependency>
    <groupId>dependency.coming</groupId>
    <artifactId>from.parent</artifactId>
    <version>0</version>
    <scope>system</scope>
    <systemPath>${project.basedir}/empty.jar</systemPath>
</dependency>

Банка може містити лише один порожній файл:

touch empty.txt
jar cvf empty.txt

Дякую за вашу відповідь, у Windows 10 мені довелося notepad empty.classтоді запустити, jar cvf empty.jar empty.classщоб створити порожню банку.
Рів

1
Це виглядає як погана практика
Piotr Żak

6

Ви спробували явно оголосити потрібну версію mail.jar? Розв’язання залежності Мейвена має використовувати це для вирішення залежності у всіх інших версіях.

<project>
  <modelVersion>4.0.0</modelVersion>
  <groupId>test</groupId>
  <artifactId>jruby</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <parent>
        <artifactId>base</artifactId>
        <groupId>es.uniovi.innova</groupId>
        <version>1.0.0</version>
    </parent>
    <dependencies>          
        <dependency>
            <groupId>javax.mail</groupId>
            <artifactId>mail</artifactId>
            <version>VERSION-#</version>
            <scope>provided</scope>
        </dependency> 
        <dependency>
            <groupId>com.liferay.portal</groupId>
            <artifactId>ALL-DEPS</artifactId>
            <version>1.0</version>
            <scope>provided</scope>
            <type>pom</type>
        </dependency>
    </dependencies>
</project>

1
Ваш підхід, як рішення Паскаля №2 також є дійсним, насправді ви також врахували, що залежність від пошти повинна оголошуватися як надана. Дякую.
Мігель

Запропонований обсяг не працював для мене. Я використав тест на обсяг, будь ласка, перевірте мою відповідь. stackoverflow.com/a/55970293/4587961
Ян Khonski

3

Найкраще зробити так, щоб залежність, яку не завжди хочеться успадкувати, непридатна.

Ви можете зробити це, позначивши їх у батьківській пам’яті з наданим обсягом.

Якщо ви все ще хочете, щоб батьки могли керувати версіями цих деп, ви можете використовувати <dependencyManagement>тег для встановлення потрібних версій без явного їх успадкування або передачі цього спадку разом з дітьми.


1

Коли ви закликаєте пакет, але не хочете деяких його залежностей, ви можете зробити так, як це (в цьому випадку я не хотів, щоб старий log4j був доданий, тому що мені потрібно було використовувати новий):

<dependency>
  <groupId>package</groupId>
  <artifactId>package-pk</artifactId>
  <version>${package-pk.version}</version>

  <exclusions>
    <exclusion>
      <groupId>org.apache.logging.log4j</groupId>
      <artifactId>log4j-core</artifactId>
    </exclusion>
    <exclusion>
      <groupId>org.apache.logging.log4j</groupId>
      <artifactId>log4j-api</artifactId>
    </exclusion>
  </exclusions>
</dependency>

<!-- LOG4J -->
<dependency>
  <groupId>org.apache.logging.log4j</groupId>
  <artifactId>log4j-core</artifactId>
  <version>2.5</version>
</dependency>
<dependency>
  <groupId>org.apache.logging.log4j</groupId>
  <artifactId>log4j-api</artifactId>
  <version>2.5</version>
</dependency>

Це працює для мене ... але я досить новачок у java / maven, тому, можливо, це не оптимально.


Ласкаво просимо в Stack Overflow, і не дозволяйте грубим людям, яких я постійно відхиляю, мої запитання відштовхують вас від публікації.
Шрідхар Сарнобат

1

Мені справді потрібно було зробити цю брудну справу ... Ось як

Я переосмислив ці залежності із розмахом test. Область застосування providedдля мене не працювала.

Ми використовуємо плагін Spring Boot для створення жиру. У нас є загальний модуль, який визначає загальні бібліотеки, наприклад Springfox swagger-2. Мій супер-сервіс повинен мати батьківських спільних (він не хоче цього робити, але компанія встановлює правила!)

Тож у мого батька чи спільноти є пом.

<dependencyManagement>

    <!- I do not need Springfox in one child but in others ->

    <dependencies>
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <version>${swagger.version}</version>
            <exclusions>
                <exclusion>
                    <groupId>com.google.guava</groupId>
                    <artifactId>guava</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
            <version>${swagger.version}</version>
        </dependency>
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-bean-validators</artifactId>
            <version>${swagger.version}</version>
        </dependency>

       <!- All services need them ->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>${junit.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-ooxml</artifactId>
            <version>${apache.poi.version}</version>
        </dependency>
    </dependencies>
</dependencyManagement>

І мій супер-сервіс пом.

<name>super-service</name>
<parent>
    <groupId>com.company</groupId>
    <artifactId>common</artifactId>
    <version>1</version>
</parent>

<dependencies>

    <!- I don't need them ->

    <dependency>
        <groupId>io.springfox</groupId>
        <artifactId>springfox-swagger2</artifactId>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>io.springfox</groupId>
        <artifactId>springfox-bean-validators</artifactId>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>io.springfox</groupId>
        <artifactId>springfox-core</artifactId>
        <version>2.8.0</version>
        <scope>test</scope>
    </dependency>

    <!- Required dependencies ->

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
     <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
    </dependency>
    <dependency>
        <groupId>org.apache.poi</groupId>
        <artifactId>poi-ooxml</artifactId>
    </dependency>
</dependencies>

Це розмір остаточного артефакту жиру

82.3 MB (86,351,753 bytes) - redefined dependency with scope test
86.1 MB (90,335,466 bytes) - redefined dependency with scope provided
86.1 MB (90,335,489 bytes) - without exclusion

Також цю відповідь варто згадати - я хотів це зробити, але я лінивий ... https://stackoverflow.com/a/48103554/4587961


0

Ми можемо додати батьківський пом як залежність від типу пом і зробити виключення з цього приводу. Тому що все-таки завантажується батьківська пом. Це працювало для мене

<dependency>
  <groupId>com.abc.boot</groupId>
  <artifactId>abc-boot-starter-parent</artifactId>
  <version>2.1.5.RELEASE</version>
  <type>pom</type>
  <exclusions>
    <exclusion>
      <groupId>com.google.code.gson</groupId>
      <artifactId>gson</artifactId>
    </exclusion>
  </exclusions>   
</dependency>
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.