Этап 3 — Spring Boot: автоконфигурация без магии
Spring Boot нужен не для того, чтобы разработчик перестал понимать настройку приложения. Он нужен, чтобы типовые настройки создавались автоматически по понятным правилам. Если в проекте есть web-зависимости, Boot готовит web-приложение. Если есть JPA и драйвер базы данных, Boot пытается подготовить DataSource, JPA-инфраструктуру и репозитории. Если подключён Security starter, Boot добавляет базовую security-настройку.
Новичку важно сразу запомнить: Boot не угадывает желания разработчика. Он смотрит на зависимости, классы, свойства и уже созданные Bean-ы, а потом принимает решение. Поэтому автоконфигурация — это не магия, а набор if-условий вокруг обычного Spring container.
Что происходит при старте Boot-приложения
Запуск обычно начинается с класса, помеченного @SpringBootApplication. Эта аннотация объединяет три роли. Первая роль — объявить класс как источник конфигурации. Вторая — включить component scanning, чтобы Spring нашёл ваши @Controller, @Service, @Repository, @Component и другие компоненты. Третья — включить auto-configuration.
После этого Boot собирает список возможных автоконфигураций и проверяет, какие из них подходят текущему приложению. Если условия выполняются, конфигурация активируется и регистрирует Bean-ы. Если условия не выполняются, она пропускается. Например, web-конфигурация не нужна консольному приложению, а JPA-конфигурация не нужна проекту без JPA-зависимостей.
Именно поэтому добавление одной зависимости в build.gradle или pom.xml может изменить поведение приложения. Вы добавили библиотеку, новый класс появился в classpath, и условие вида @ConditionalOnClass стало истинным. Boot увидел новый признак и включил дополнительную конфигурацию.
Почему Boot создаёт DataSource, Security и Web
Boot принимает решения по нескольким признакам. Classpath показывает, какие библиотеки подключены к проекту. Bean presence показывает, создал ли разработчик уже собственный Bean. Properties показывают значения из конфигурации, например URL базы данных или включение конкретной функции. Application type показывает, какое приложение запускается: servlet web, reactive web или не web-приложение.
Если есть spring-boot-starter-web, Boot видит web-стек и готовит MVC-инфраструктуру, JSON-конвертеры и embedded server. Если есть spring-boot-starter-data-jpa и JDBC-драйвер, Boot пытается настроить подключение к базе и JPA. Если есть spring-boot-starter-security, Boot включает базовую защиту. Это поведение детерминировано: его можно объяснить через зависимости и свойства.
Роль starter dependencies
Starter — это удобная зависимость, которая подтягивает набор библиотек для типовой задачи. Например, spring-boot-starter-web подтягивает Spring MVC, JSON-обработку, validation и встроенный сервер. spring-boot-starter-data-jpa подтягивает Spring Data JPA, Hibernate и связанные библиотеки.
Стартеры решают две задачи: дают готовый набор библиотек и подбирают совместимые версии. Разработчику не нужно вручную собирать десяток зависимостей и проверять, подходят ли их версии друг другу. Но стартер не является пустой меткой. Он меняет classpath, а значит может включить новые автоконфигурации. Поэтому после добавления starter полезно понимать, какие возможности он принёс в приложение.
| Признак | Пример | Что может сделать Boot |
|---|---|---|
| Класс есть в classpath | Подключён spring-boot-starter-web | Создать web-инфраструктуру и embedded Tomcat |
| Bean уже создан | Разработчик объявил свой DataSource | Не создавать стандартный DataSource |
| Property задана | spring.datasource.url | Использовать значение для подключения к БД |
| Активен профиль | dev или prod | Загрузить профильный файл конфигурации |
AutoConfiguration.imports и условные аннотации
В современных версиях Spring Boot список автоконфигураций находится в файлах AutoConfiguration.imports внутри подключённых библиотек. Новичку не нужно начинать с ручного редактирования этого файла. Важно понимать его роль: это список классов, которые Boot может рассмотреть при старте.
Но наличие класса в списке ещё не означает, что конфигурация точно включится. Каждый такой класс обычно содержит условия. @ConditionalOnClass означает: включить конфигурацию только если нужный класс есть в classpath. @ConditionalOnBean означает: включить только если уже существует нужный Bean. @ConditionalOnMissingBean означает: создать стандартный Bean только если разработчик не создал свой. @ConditionalOnProperty означает: включить поведение только при определённом значении настройки.
Проще всего думать так: AutoConfiguration.imports отвечает на вопрос «какие настройки Boot вообще умеет попробовать», а conditional annotations отвечают на вопрос «какие из них подходят именно этому приложению сейчас». Если Bean не создался, сначала нужно проверить не код бизнес-логики, а условия: есть ли зависимость, есть ли нужное свойство, активен ли правильный профиль, не создан ли конфликтующий Bean.
Внешняя конфигурация и профили
application.yml или application.yaml — это основной файл настроек Spring Boot приложения. Обычно он лежит в src/main/resources. В нём пишут значения, которые должны меняться без переписывания Java-кода: порт сервера, настройки подключения к базе, уровень логирования, параметры внешних сервисов, включение или отключение функций, настройки Actuator и Security.
Пример идеи, а не полный production-файл:
server:
port: 8080
spring:
datasource:
url: jdbc:postgresql://localhost:5432/app
username: app
logging:
level:
org.springframework.web: INFO
Такой файл нужен, чтобы код оставался одинаковым, а поведение можно было менять настройками. Локально приложение может ходить в локальную базу, в тестах — в тестовую, а в production — в production-базу. Для этого используют профили.
Профиль — это имя окружения или режима запуска: dev, test, prod, local. Для профиля создают отдельный файл рядом с основным: application-dev.yml, application-test.yml, application-prod.yml. Сначала Boot читает общий application.yml, затем применяет файл активного профиля и переопределяет совпадающие значения.
Например, в application.yml можно оставить общие настройки приложения, а в application-dev.yml указать локальную базу и более подробные логи. Активировать профиль можно через property spring.profiles.active=dev, переменную окружения SPRING_PROFILES_ACTIVE=dev, аргумент командной строки или настройки запуска в IDE.
Embedded server и Actuator
В классическом Java web-подходе приложение часто собирали в WAR-файл и разворачивали во внешний сервер приложений. Сначала администратор устанавливал Tomcat или другой сервер, затем туда помещали приложение. Spring Boot чаще использует другой подход: сервер встроен внутрь приложения. Когда вы подключаете spring-boot-starter-web, Boot добавляет embedded Tomcat по умолчанию.
Embedded Tomcat — это обычный web-сервер, который запускается вместе с вашим приложением. Поэтому Spring Boot приложение можно собрать в jar и запустить командой вроде java -jar app.jar. При старте поднимается JVM, создаётся Spring context, запускается Tomcat, открывается порт, и приложение начинает принимать HTTP-запросы. Это удобно для локальной разработки, Docker, cloud deployments и CI/CD, потому что артефакт содержит всё необходимое для запуска web-приложения.
Actuator — это набор служебных endpoints для наблюдения за приложением. Он помогает понять, живо ли приложение, какие метрики собираются, какие health checks проходят, какие Bean-ы и properties есть в context. Например, endpoint health часто используется load balancer-ом или Kubernetes, чтобы решить, можно ли отправлять трафик в конкретный экземпляр приложения. Actuator не заменяет логи и мониторинг, но даёт стандартную operational-информацию.
Практический пример
Ты добавляешь в проект spring-boot-starter-data-jpa и драйвер PostgreSQL. После перезапуска Boot видит JPA и драйвер в classpath. Затем он ищет настройки spring.datasource.*. Если URL, пользователь и другие нужные параметры заданы корректно, Boot создаёт DataSource, EntityManagerFactory, transaction manager и инфраструктуру репозиториев.
Если приложение не стартует, не нужно сразу переписывать сервисы. Сначала проверь простые причины: подключён ли драйвер, правильно ли написан URL, активен ли нужный профиль, не лежат ли production-настройки в dev-файле, не объявлен ли собственный Bean, который изменил стандартное поведение.
Практичные правила для новичка
Когда поведение Boot непонятно, начни с входных данных для автоконфигурации. Проверь зависимости, активный профиль, значения в application.yml и профильных файлах. Это обычно быстрее, чем искать ошибку в контроллере или сервисе.
Если настройка отличается между окружениями, не смешивай всё в одном файле. Общие значения держи в application.yml, а различия выноси в application-dev.yml, application-test.yml или application-prod.yml. Так проще увидеть, почему локальный запуск отличается от production.
Если Boot создал стандартный Bean, а тебе нужно другое поведение, сначала попробуй изменить property. Если property недостаточно, объяви свой Bean точечно. Отключать целый auto-configuration модуль стоит только тогда, когда ты понимаешь, какую инфраструктуру он создавал и почему она мешает.
Итог этапа
Spring Boot — это слой, который автоматически настраивает Spring-приложение по зависимостям, свойствам, профилям и уже созданным Bean-ам. Он создаёт типовую инфраструктуру, но делает это по проверяемым условиям. Когда понятны classpath, starters, application.yml, profiles, embedded server и Actuator, Boot перестаёт выглядеть как магия и становится предсказуемым инструментом.
Чек-лист понимания
- Могу объяснить, почему добавление starter меняет поведение приложения.
- Понимаю, что
AutoConfiguration.importsдаёт список возможных автоконфигураций, а условные аннотации выбирают подходящие. - Могу объяснить, что пишут в
application.ymlи зачем нужны профильные файлы. - Понимаю, что embedded Tomcat запускается внутри jar-приложения.
- Могу назвать, зачем нужен Actuator в работающем приложении.
Вопросы для самопроверки
- Почему Boot может создать Bean после добавления новой зависимости?
- Чем
application.ymlотличается отapplication-dev.yml? - Почему embedded Tomcat упрощает запуск Spring Boot web-приложения?