Что делает аннотация @ComponentScan?
4. excludeFilters → для тестов 5. useDefaultFilters = false → кастомные аннотации 6. ASM → не загружает классы, читает байт-код
🟢 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
- basePackageClasses → типобезопасно
- spring-context-indexer → для больших проектов
- Ограничьте пакеты → не сканируйте лишнее
- excludeFilters → для тестов
- useDefaultFilters = false → кастомные аннотации
- 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]]