Ответ
<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:
- Единое управление версиями во всех модулях.
- Упрощение POM дочерних модулей.
- Предотвращение конфликтов версий.
Ответ 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>? Да затем, чувак!
- Единая версия на всех. Чтобы в одном модуле не было Spring 5.2, а в другом — 5.3, а они потом друг другу ебало набьют из-за несовместимости.
- POMы детей — чистые. Не надо в каждом модуле копипастить одни и те же
<version>1.2.3.4.5</version>. Указал в одном месте — и все довольны. - Конфликты? Какие конфликты? Maven теперь точно знает, какую версию выбрать, если две либы тянут одну и ту же зависимость, но разных версий. Берём ту, что в management прописана, и нет проблем.
Вот и вся магия. Не так страшен чёрт, как его малюют. Главное — не путать, где ты реально ставишь пиво, а где просто читаешь мораль про то, какое пиво нужно пить.