Питання 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. Що таке стартер в Spring Boot]]
  • [[26. Що робить анотація @Autowired]]