Питання 23 · Розділ 5

Що робить анотація @ComponentScan?

4. excludeFilters → для тестів 5. useDefaultFilters = false → кастомні анотації 6. ASM → не завантажує класи, читає байт-код

Мовні версії: English Russian Ukrainian

🟢 Junior Level

@ComponentScan — вказує Spring, в яких пакетах шукати біни (@Component, @Service, @Repository).

@SpringBootApplication  // Вже включає @ComponentScan
public class Application { }

// Ручне налаштування:
@ComponentScan(basePackages = "com.example.services")

Правило:

  • @SpringBootApplication сканує поточний пакет та всі підпакети
  • Зазвичай не потрібно налаштовувати вручну

🟡 Middle Level

Як працює сканування

ClassPathBeanDefinitionScanner:
  1. Читає .class файли через ASM (бібліотека для читання байт-коду без завантаження класів в JVM)
  // Це важливо: класи не проходять повну ініціалізацію JVM, їх static блоки не виконуються.
  // Spring тільки читає анотації з .class файлів.
  2. Шукає анотації @Component, @Service...
  3. Створює BeanDefinition
  4. НЕ завантажує класи в JVM!

Налаштування

// Сканувати конкретні пакети
@ComponentScan(basePackages = {"com.example.a", "com.example.b"})

// Типобезпечно (рекомендується!)
@ComponentScan(basePackageClasses = MyMarkerInterface.class)

// Виключити класи
@ComponentScan(excludeFilters = @Filter(Type.ASSIGNABLE_TYPE, classes = Config.class))

spring-context-indexer

Для великих проектів → повільне сканування

Залежність: spring-context-indexer
  → При компіляції створює META-INF/spring.components
  → Spring читає список замість сканування
  → Старт в 2-3 рази швидший!

🔴 Senior Level

ConfigurationClassPostProcessor

Запускає сканування:
  1. Парсить @Configuration класи
  2. Обробляє @Import
  3. Запускає ClassPathBeanDefinitionScanner
  4. Реєструє BeanDefinition

Фільтрація

@ComponentScan(
    useDefaultFilters = false,  // Вимкнути @Component
    includeFilters = @Filter(MyCustomAnnotation.class)
)
// Це корисно, якщо ви хочете сканувати тільки свої кастомні анотації
// та ігнорувати стандартні @Component/@Service. Усі стандартні біни
// при цьому НЕ зареєструються!

Production Experience

Реальний сценарій: 10 секунд на сканування

5000 класів → ASM сканування → 10 секунд
Рішення: spring-context-indexer
Результат: 2 секунди

Best Practices

  1. basePackageClasses → типобезпечно
  2. spring-context-indexer → для великих проектів
  3. Обмежте пакети → не скануйте зайве
  4. excludeFilters → для тестів
  5. useDefaultFilters = false → кастомні анотації
  6. ASM → не завантажує класи, читає байт-код

Резюме для Senior

  • @ComponentScan → пошук бінів у пакетах
  • ASM → читання байт-коду, не рефлексія
  • ConfigurationClassPostProcessor → запускає сканування
  • spring-context-indexer → прискорення старту
  • basePackageClasses → типобезпечно
  • Фільтри → include/exclude

🎯 Шпаргалка для інтерв’ю

Обов’язково знати:

  • @ComponentScan шукає @Component, @Service, @Repository, @Controller у вказаних пакетах
  • @SpringBootApplication вже включає @ComponentScan поточного пакета та підпакетів
  • ASM читає байт-код .class файлів — класи НЕ завантажуються в JVM, static блоки НЕ виконуються
  • ConfigurationClassPostProcessor запускає сканування на ранній фазі
  • spring-context-indexer створює META-INF/spring.components при компіляції — старт в 2-3 рази швидший
  • basePackageClasses — типобезпечна альтернатива рядковим пакетам
  • includeFilters / excludeFilters — тонке налаштування сканування

Часті уточнюючі запитання:

  • Чому Spring не завантажує класи при скануванні? — ASM читає тільки анотації з байт-коду, це швидше та безпечніше (static блоки не виконуються).
  • Як прискорити сканування у великому проекті? — spring-context-indexer: мета-файл створюється при компіляції, Spring читає його замість обходу classpath.
  • Що буде з excludeFilters = @Filter(Type.ASSIGNABLE_TYPE, classes = Config.class)? — Клас Config не буде зареєстрований як бін.
  • Навіщо потрібен useDefaultFilters = false? — Щоб ігнорувати стандартні @Component та сканувати тільки кастомні анотації.

Червоні прапорці (НЕ говорити):

  • «ComponentScan завантажує всі класи через рефлексію» — ні, ASM читає байт-код без завантаження.
  • «Потрібно завжди налаштовувати @ComponentScan вручну» — @SpringBootApplication вже сканує.
  • «spring-context-indexer — це runtime-оптимізація» — ні, індекс створюється при компіляції.
  • «basePackages безпечніше basePackageClasses» — навпаки, basePackageClasses ловить помилки на компіляції.

Пов’язані теми:

  • [[21. Як працює @SpringBootApplication]]
  • [[25. В чому різниця між @Component, @Service, @Repository, @Controller]]
  • [[24. Що таке @Configuration клас]]
  • [[26. Що робить анотація @Autowired]]