Урок по треку Spring и Spring Boot 7 мин

Spring Boot и автоконфигурация

Стартеры, @SpringBootApplication, @Conditional, свойства и профили, Actuator.

Spring Boot отвечает на вопрос «как запустить Spring-приложение без километра конфигурации». На собесе спрашивают, как работает автоконфигурация, откуда берутся бины, которые вы не объявляли, и как устроены свойства и профили.

Что даёт Boot

  • Стартеры: spring-boot-starter-web, -data-jpa, -security подтягивают согласованный набор зависимостей с проверенными версиями (BOM spring-boot-dependencies).
  • Автоконфигурация: бины инфраструктуры создаются сами, если в classpath есть нужная библиотека и вы не объявили свой бин.
  • Встроенный сервер: Tomcat по умолчанию (можно Jetty или Undertow), приложение это обычный исполняемый jar.
  • Внешняя конфигурация: свойства из файлов, переменных окружения, аргументов.
  • Actuator: health, метрики, info.

@SpringBootApplication

Это три аннотации в одной:

  • @SpringBootConfiguration (по сути @Configuration);
  • @EnableAutoConfiguration включает автоконфигурацию;
  • @ComponentScan сканирует пакет класса и все вложенные.

Отсюда частая ошибка: класс приложения лежит в com.shop.app, а сервисы в com.shop.service. Сканирование их не найдёт.

Как работает автоконфигурация

Список классов автоконфигурации лежит в META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports внутри jar-ов (до Boot 2.7 был spring.factories). Каждый такой класс помечен @AutoConfiguration и обвешан условиями:

@AutoConfiguration
@ConditionalOnClass(DataSource.class)
@EnableConfigurationProperties(DataSourceProperties.class)
public class DataSourceAutoConfiguration {
    @Bean
    @ConditionalOnMissingBean
    DataSource dataSource(DataSourceProperties props) { ... }
}

Основные условия:

  • @ConditionalOnClass / @ConditionalOnMissingClass: есть ли класс в classpath;
  • @ConditionalOnBean / @ConditionalOnMissingBean: есть ли уже такой бин (ваш бин побеждает дефолтный);
  • @ConditionalOnProperty: включено ли свойство;
  • @ConditionalOnWebApplication.

Автоконфигурации обрабатываются после ваших конфигураций, поэтому @ConditionalOnMissingBean видит ваши бины. Посмотреть, что сработало и почему, можно через --debug (отчёт условий) или эндпоинт Actuator /actuator/conditions. Отключить конкретную: @SpringBootApplication(exclude = DataSourceAutoConfiguration.class).

Свойства и профили

Источники с приоритетом (позднее перекрывает раннее, упрощённо): application.yml в jar, application-{profile}.yml, файлы рядом с jar, переменные окружения, аргументы командной строки. Переменная SPRING_DATASOURCE_URL перекрывает spring.datasource.url (relaxed binding).

Типобезопасные настройки через @ConfigurationProperties:

@ConfigurationProperties(prefix = "payments")
public record PaymentProps(String baseUrl, Duration timeout, int retries) {}

Это лучше россыпи @Value("${...}"): валидация (@Validated), подсказки в IDE, один объект вместо десятка полей.

Профили (spring.profiles.active=prod) включают свои файлы свойств и бины с @Profile("prod"). Секреты не хранят в application.yml в репозитории: они приходят из переменных окружения или хранилища секретов.

Actuator

/actuator/health (с группами liveness и readiness для Kubernetes), /actuator/metrics и /actuator/prometheus (Micrometer), /actuator/info. По HTTP по умолчанию открыт только health. Открывать env, heapdump, beans наружу опасно: там секреты и внутренности.

Частые ошибки

  • Пакеты вне сканирования.
  • Свой бин того же типа выключает автоконфигурацию, и пропадают нужные настройки по умолчанию.
  • @Value по всему коду вместо @ConfigurationProperties.
  • Открытые наружу эндпоинты Actuator.

Что спросят на собесе

  • Что такое стартер и что внутри @SpringBootApplication?
  • Как работает автоконфигурация, где Boot берёт список классов?
  • Что такое @ConditionalOnMissingBean и как переопределить бин по умолчанию?
  • Как устроен приоритет свойств, как работают профили?
  • Зачем Actuator и что нельзя открывать наружу?

Закрепите за 5 минут

После урока в тренажёре 3-5 проверочных вопросов, дальше модуль уходит в повторения.