В чем разница между секциями dependencyManagement и dependencies в Maven POM?

Ответ

<dependencies> — секция для прямого объявления зависимостей, которые будут добавлены в classpath модуля. <dependencyManagement> — секция для централизованного управления версиями и scope зависимостей в многомодульных проектах, без их автоматического добавления.

Ключевые отличия:

  • Назначение: dependencies добавляет зависимости, dependencyManagement управляет их версиями.
  • Наследование: Зависимости из dependencies наследуются дочерними модулями. Версии из dependencyManagement наследуются, но сами зависимости — нет.
  • Использование: В дочернем модуле в dependencies можно указать зависимость без версии, если она определена в родительском dependencyManagement.

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

Родительский POM (pom.xml):

<project>
    <groupId>com.example</groupId>
    <artifactId>parent-project</artifactId>
    <packaging>pom</packaging>

    <dependencyManagement>
        <dependencies>
            <!-- Управление версиями -->
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-core</artifactId>
                <version>5.3.23</version>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <dependencies>
        <!-- Зависимость для всех модулей -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.24</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>
</project>

Дочерний модуль (service-module/pom.xml):

<project>
    <parent>
        <artifactId>parent-project</artifactId>
        <groupId>com.example</groupId>
    </parent>

    <dependencies>
        <!-- Версия унаследуется из dependencyManagement -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
        </dependency>
        <!-- Lombok тоже добавится, т.к. он в dependencies родителя -->
    </dependencies>
</project>

Преимущества dependencyManagement:

  1. Единое управление версиями во всех модулях.
  2. Упрощение POM дочерних модулей.
  3. Предотвращение конфликтов версий.

Ответ 18+ 🔞

О, ну ты держись, сейчас я тебе такую простыню накатаю про эти две штуки, что ты сам начнёшь в них разбираться, как в своей зубной щётке. Погнали.

Представь себе, что <dependencies> — это ты, такой щедрый, пришёл в бар и сразу всем на столе кричишь: «Ребят, я ставлю! Всем пиво, мне виски, а этому лысому — двойной бурбон!». То есть ты сразу, нахуй, объявляешь, что вот эти либы — они прям тут, в проекте, будут. Maven их скачает и начнёт юзать. Всё просто и прямолинейно.

А теперь <dependencyManagement> — это ты не в баре, а на семейном совете. Ты такой главный по тарелочкам, и заявляешь: «Так, слушайте сюда все, мои дорогие модули-детки! Запомните раз и навсегда: если кто-то из вас вдруг захочет либу «Spring-Core», то берите ТОЛЬКО версию 5.3.23, и ни одной другой, блядь! А если кто возьмёт «Guava» — то только 31.1-jre! Понятно?». Но при этом ты им пиво НЕ ставишь. Ты просто устанавливаешь правила, стандарты, версии. Это как устав в армии, только для зависимостей.

Короче, разница на пальцах:

  • <dependencies> в родительском POM: «Дети, вот вам конфеты (зависимости), жуйте на здоровье, они уже у вас в кармане».
  • <dependencyManagement> в родительском POM: «Дети, если решите купить конфеты, то только «Марс» и только за 50 рублей. А покупать или нет — решайте сами».

Наследование — это вообще отдельная песня, ебушки-воробушки:

  • Что в <dependencies> родителя — то автоматом лезет в classpath всех детей. Хотят они того или нет. Ломбок, например, навяжется всем, как назойливая тёща.
  • Что в <dependencyManagement> родителя — дети наследуют только ПРАВИЛА (версии, scope, exclusions). Но чтобы либа реально появилась, ребёнок должен в своём собственном <dependencies> написать: «Пап, я хочу ту самую Spring-Core, про которую ты говорил». И версию можно не указывать — Maven её сам подтянет из папиных правил. Удобно, ёпта!

Пример, чтобы вообще всё встало на свои места:

Вот родительский pom.xml, большой и важный:

<project>
    <groupId>com.example</groupId>
    <artifactId>big-boss-project</artifactId>
    <packaging>pom</packaging> <!-- Он же родитель, он собирает детей в кучу -->

    <dependencyManagement>
        <dependencies>
            <!-- Это не зависимость, это ПРИКАЗ по версиям -->
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-core</artifactId>
                <version>5.3.23</version> <!-- Запомнили? Только эту версию! -->
            </dependency>
        </dependencies>
    </dependencyManagement>

    <dependencies>
        <!-- А это реальная зависимость, которая влезет ко всем детям, как банный лист -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.24</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>
</project>

А вот его сыночек-модуль service-module/pom.xml:

<project>
    <parent>
        <artifactId>big-boss-project</artifactId>
        <groupId>com.example</groupId>
    </parent>

    <dependencies>
        <!-- Хочу spring-core! Версию не пишу, ибо папа в management её уже указал.
             Maven сам полезет в папины правила и возьмёт 5.3.23. Красота! -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
        </dependency>
        <!-- А ломбок тут уже есть, он от папы прибежал автоматом,
             потому что был в его <dependencies>. Его даже объявлять не надо. -->
    </dependencies>
</project>

И зачем этот цирк с <dependencyManagement>? Да затем, чувак!

  1. Единая версия на всех. Чтобы в одном модуле не было Spring 5.2, а в другом — 5.3, а они потом друг другу ебало набьют из-за несовместимости.
  2. POMы детей — чистые. Не надо в каждом модуле копипастить одни и те же <version>1.2.3.4.5</version>. Указал в одном месте — и все довольны.
  3. Конфликты? Какие конфликты? Maven теперь точно знает, какую версию выбрать, если две либы тянут одну и ту же зависимость, но разных версий. Берём ту, что в management прописана, и нет проблем.

Вот и вся магия. Не так страшен чёрт, как его малюют. Главное — не путать, где ты реально ставишь пиво, а где просто читаешь мораль про то, какое пиво нужно пить.