Вопрос 21 · Раздел 5

Как работает @SpringBootApplication?

4. exclude → отключение автоконфигураций 5. basePackageClasses → типобезопасное сканирование 6. FailureAnalyzer → свои сообщения об ошибках

Версии по языкам: English Russian Ukrainian

🟢 Junior Level

@SpringBootApplication — главная аннотация Spring Boot приложения.

@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

Она делает 3 вещи:

  1. @Configuration → класс является конфигурацией
  2. @EnableAutoConfiguration → Spring Boot сам настраивает бины
  3. @ComponentScan → сканирует пакеты и находит @Component, @Service

Правило:

  • Размещайте в корневом пакете
  • Все подпакеты будут просканированы

🟡 Middle Level

Анатомия

@SpringBootConfiguration    // = @Configuration для тестов
@EnableAutoConfiguration   // Автоконфигурация
@ComponentScan             // Сканирование пакетов
public @interface SpringBootApplication { }

ComponentScan поведение

// Application в com.example.app
// → Сканирует com.example.app и все подпакеты

// ❌ Сервисы в com.example.common → НЕ найдутся!
// ✅ Решение:
@SpringBootApplication(scanBasePackages = "com.example")

Процесс запуска

SpringApplication.run():
  1. Создание ApplicationContext → контейнер для всех бинов
  2. Загрузка Environment → application.properties, переменные окружения, CLI-аргументы
  3. Refresh Context → ядро Spring: регистрирует BPP, создаёт ВСЕ бины, разрешает зависимости
  4. Запуск встроенного сервера → Tomcat/Jetty/Undertow на указанном порту
  5. Выполнение CommandLineRunner → ваш код после полного старта контекста

proxyBeanMethods

// По умолчанию: true (CGLIB прокси)
// Для оптимизации:
@SpringBootConfiguration(proxyBeanMethods = false)
// → Быстрее старт, меньше памяти: по умолчанию Spring создаёт CGLIB-подкласс
// для каждого @Configuration класса (Full mode). Генерация байт-кода занимает
// время и память. При proxyBeanMethods = false вызовы @Bean методов идут напрямую.
// → Но @Bean методы создают новые объекты при вызове

🔴 Senior Level

Refresh Context

Сердце запуска:
  1. BeanFactoryPostProcessor → изменение BeanDefinition
  2. BeanPostProcessor регистрация
  3. Сканирование + автоконфигурация
  4. Создание бинов
  5. Запуск сервера

FailureAnalyzers

Spring Boot ловит ошибки старта:
  → "Port already in use"
  → "DataSource not configured"
  
→ Красивые сообщения вместо стек-трейса
→ Можно создать свои анализаторы

Production Experience

Реальный сценарий: ComponentScan не нашёл бины

Application → com.example.app
Services → com.example.services
→ Бины не найдены!

Решение:
  @SpringBootApplication(scanBasePackages = "com.example")

Best Practices

  1. Корневой пакет → com.example.app
  2. scanBasePackages → если бины в других пакетах
  3. proxyBeanMethods = false — если @Bean методы не вызывают друг друга (иначе сломается singleton-семантика: каждый вызов создаст новый объект).
  4. exclude → отключение автоконфигураций
  5. basePackageClasses → типобезопасное сканирование
  6. FailureAnalyzer → свои сообщения об ошибках

Резюме для Senior

  • @SpringBootApplication = Configuration + AutoConfig + ComponentScan
  • Местоположение → определяет область сканирования
  • Refresh Context → ключевая фаза создания бинов
  • proxyBeanMethods → оптимизация старта
  • FailureAnalyzers → понятные ошибки
  • scanBasePackages → для бинов вне корневого пакета

🎯 Шпаргалка для интервью

Обязательно знать:

  • @SpringBootApplication = @Configuration + @EnableAutoConfiguration + @ComponentScan
  • Размещать в корневом пакете — сканирует все подпакеты
  • SpringApplication.run(): создание контекста → загрузка Environment → Refresh Context → запуск сервера → CommandLineRunner
  • proxyBeanMethods = false ускоряет старт, но ломает singleton при вызовах @Bean методов друг друга
  • scanBasePackages / basePackageClasses — если бины вне корневого пакета
  • Refresh Context — ключевая фаза: BPP регистрация, автоконфигурация, создание бинов
  • FailureAnalyzers дают читаемые ошибки вместо стек-трейса

Частые уточняющие вопросы:

  • Что произойдёт, если разместить Application не в корневом пакете? — Компоненты в других ветках пакетов не будут найдены ComponentScan.
  • Зачем нужен proxyBeanMethods? — CGLIB-прокси обеспечивает singleton-семантику при вызовах @Bean методов; отключение ускоряет старт.
  • Можно ли отключить автоконфигурацию? — Да, через @SpringBootApplication(exclude = …).
  • Что делает Refresh Context? — Регистрирует BeanPostProcessor, создаёт все бины, запускает сервер.

Красные флаги (НЕ говорить):

  • «@SpringBootApplication просто запускает приложение» — нет, это 3 аннотации в одной.
  • «Можно ставить @SpringBootApplication на любой класс» — только на конфигурационный класс с main().
  • «proxyBeanMethods = false всегда лучше» — нет, сломается singleton при меж-@Bean вызовах.
  • «ComponentScan загружает все классы в JVM» — нет, ASM читает только байт-код.

Связанные темы:

  • [[23. Что делает аннотация @ComponentScan]]
  • [[24. Что такое @Configuration класс]]
  • [[22. Что такое starter в Spring Boot]]
  • [[26. Что делает аннотация @Autowired]]