Maven, зависимости и стартеры
Стартеры Spring Boot — это «комплекты под задачу»: одна зависимость тянет за собой согласованный набор библиотек нужных версий.
Суть: вместо ручного подбора десятка библиотек вы подключаете один стартер. Parent POM и BOM гарантируют, что версии не конфликтуют.
Управление зависимостями в Java — историческая боль. Библиотека A требует версию 2 библиотеки X, библиотека B — версию 3, и приложение падает с загадочной ошибкой. Эта проблема называется «dependency hell». Spring Boot решает её через две вещи: стартеры и управление версиями.
Что такое стартер
Стартер — это специальная зависимость, которая сама по себе почти не содержит кода, но тянет за собой набор других библиотек под конкретную задачу. Например, spring-boot-starter-web приносит Spring MVC, встроенный Tomcat, Jackson для JSON и валидацию. Вам не нужно знать названия и версии всех этих библиотек — стартер собрал их за вас.
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
</dependencies>
Заметьте: у зависимостей нет тега <version>. Откуда же Maven знает версию? Из parent POM.
Как работает под капотом: parent POM и BOM
В каждом проекте Spring Boot есть строка с родителем:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.3.0</version>
</parent>
Этот spring-boot-starter-parent содержит BOM (Bill of Materials — «ведомость материалов») — большую таблицу, где для сотен библиотек прописаны проверенные, совместимые версии. Когда вы подключаете стартер без версии, Maven берёт её из BOM. Так гарантируется, что Jackson, Hibernate, Tomcat и всё остальное собраны в комбинации, которую команда Spring протестировала.
spring-boot-starter-parent (версия 3.3.0)
|
+-- BOM: таблица версий
| jackson = 2.17.x
| hibernate = 6.5.x
| tomcat = 10.1.x
| ... сотни библиотек
v
Ваш проект подключает стартеры БЕЗ версий
|
+-- starter-web --> tomcat, jackson, spring-mvc
+-- starter-data-jpa --> hibernate, spring-data
v
Maven берёт версии из BOM => конфликтов нет
Смоделируем механику разрешения версий на простом примере. По сути BOM — это словарь «библиотека → версия», а стартеры просто перечисляют, что им нужно:
# BOM: согласованная таблица версий
bom = {
"jackson": "2.17.1",
"hibernate": "6.5.2",
"tomcat": "10.1.24",
"spring-mvc": "6.1.8",
}
# Стартеры перечисляют нужные библиотеки (без версий)
starters = {
"starter-web": ["tomcat", "jackson", "spring-mvc"],
"starter-data-jpa": ["hibernate"],
}
def resolve(selected_starters):
libs = {}
for st in selected_starters:
for lib in starters[st]:
libs[lib] = bom[lib] # версию берём из BOM
return libs
print(resolve(["starter-web", "starter-data-jpa"]))
# Все версии согласованы между собой
Нажмите «Попробуй сам ▶» — увидите, как «стартеры» разворачиваются в конкретные библиотеки с версиями из единой ведомости.
Частые ошибки
- Указывать версию вручную. Прописав свою версию у управляемой стартером библиотеки, вы рискуете сломать совместимость, заданную BOM.
- Тянуть библиотеку напрямую вместо стартера. Лучше искать готовый стартер — он соберёт зависимости правильно.
- Менять версию Boot, не проверив changelog. Между минорными версиями (3.2 → 3.3) меняются дефолты — читайте release notes.
Best practices
- Подключайте стартеры без версий — пусть BOM управляет версиями.
- Версию Boot держите в
<parent>или в свойстве, чтобы менять её в одном месте. - Для апгрейда используйте инструменты вроде OpenRewrite — они автоматизируют миграцию.
Итог: стартеры избавляют от ручного подбора библиотек, а parent POM с BOM гарантирует совместимость версий. Это и есть «магия», благодаря которой проект Spring Boot собирается без dependency hell.