Вопрос 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]]