← Назад к вопросам
На основании чего происходит сканирование с использованием @ComponentScan
2.0 Middle🔥 201 комментариев
#Spring Framework
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
# Сканирование компонентов с @ComponentScan
Что такое @ComponentScan
@ComponentScan — это аннотация в Spring Framework, которая автоматически сканирует классы и находит компоненты Spring (beans) для их регистрации в контексте приложения.
На основании чего происходит сканирование
1. Аннотации на классах
Scan ищет классы, помеченные специальными аннотациями:
// Spring ищет эти аннотации:
@Component // Базовый компонент
@Service // Сервис
@Repository // Репозиторий (DAO)
@Controller // Контроллер
@RestController // REST контроллер
и другие...
Пример:
// Spring найдёт этот класс через @ComponentScan
@Service
public class UserService {
public User getUserById(Long id) {
// реализация
}
}
@Repository
public class UserRepository {
public User findById(Long id) {
// реализация
}
}
@RestController
public class UserController {
// контроллер
}
2. Базовый пакет (Base Package)
@ComponentScan сканирует определённый пакет и его подпакеты:
// Сканирует пакет com.example и всё внутри
@ComponentScan(basePackages = "com.example")
public class AppConfig {
}
// Или можно указать несколько пакетов
@ComponentScan(basePackages = {"com.example", "com.other"})
public class AppConfig {
}
Структура проекта:
com.example/
├── config/
│ ├── AppConfig.java ← @ComponentScan тут
│ └── SecurityConfig.java ← НАЙДЁТСЯ (в подпакете)
├── service/
│ ├── UserService.java ← НАЙДЁТСЯ (@Service)
│ └── OrderService.java ← НАЙДЁТСЯ (@Service)
├── repository/
│ ├── UserRepository.java ← НАЙДЁТСЯ (@Repository)
│ └── OrderRepository.java ← НАЙДЁТСЯ (@Repository)
└── controller/
├── UserController.java ← НАЙДЁТСЯ (@RestController)
└── OrderController.java ← НАЙДЁТСЯ (@RestController)
com.other/
├── external/
│ └── ExternalService.java ← НЕ найдётся (другой пакет)
3. Класс-ссылка (basePackageClasses)
Можно использовать класс вместо строки:
@ComponentScan(basePackageClasses = UserService.class)
public class AppConfig {
}
// Spring найдёт пакет, где находится UserService
// и будет сканировать оттуда
Это безопаснее, чем строки (рефакторинг не сломает).
4. Фильтры (Filters)
Можно включать или исключать определённые классы:
// Включить только @Service аннотированные классы
@ComponentScan(
basePackages = "com.example",
includeFilters = @ComponentScan.Filter(
type = FilterType.ANNOTATION,
classes = Service.class
)
)
public class AppConfig {
}
// Исключить классы с определённым паттерном
@ComponentScan(
basePackages = "com.example",
excludeFilters = @ComponentScan.Filter(
type = FilterType.REGEX,
pattern = ".*Test.*"
)
)
public class AppConfig {
}
Как работает процесс сканирования
Шаг 1: Определение пакета
@ComponentScan(basePackages = "com.example")
public class AppConfig {
}
// Spring знает: сканировать com.example и подпакеты
Шаг 2: Поиск файлов .class
com/example/**/*.class
↓
Найдены все .class файлы в пакете и подпакетах
Шаг 3: Проверка аннотаций
// Для каждого класса проверяется:
if (hasAnnotation(clazz, Component.class) ||
hasAnnotation(clazz, Service.class) ||
hasAnnotation(clazz, Repository.class) ||
hasAnnotation(clazz, Controller.class)) {
// Это компонент, нужно зарегистрировать
}
Шаг 4: Регистрация в контексте
// Spring создаёт Bean и регистрирует в контексте
BeanDefinition beanDef = new BeanDefinition(clazz);
contextRegistry.registerBeanDefinition("userService", beanDef);
// Теперь можно инъектировать
@Autowired
private UserService userService; // Найдётся в контексте
Полный пример
Конфигурация
@Configuration
@ComponentScan(basePackages = "com.example")
public class AppConfig {
}
Сканируемые компоненты
// com/example/service/UserService.java
@Service
public class UserService {
public User getUserById(Long id) {
return new User(id, "John");
}
}
// com/example/repository/UserRepository.java
@Repository
public class UserRepository {
public User save(User user) {
System.out.println("Сохранён: " + user);
return user;
}
}
// com/example/controller/UserController.java
@RestController
@RequestMapping("/users")
public class UserController {
@Autowired
private UserService userService;
@GetMapping("/{id}")
public User getUser(@PathVariable Long id) {
return userService.getUserById(id);
}
}
Как это работает
1. Spring запускается
2. Видит @ComponentScan(basePackages = "com.example")
3. Сканирует папку com.example/**
4. Находит UserService (@Service) → регистрирует bean
5. Находит UserRepository (@Repository) → регистрирует bean
6. Находит UserController (@RestController) → регистрирует bean
7. UserController хочет UserService (@Autowired)
8. Spring вводит найденный bean
9. Всё работает!
Когда @ComponentScan нужна
Используется в Java конфигурации
@Configuration
@ComponentScan(basePackages = "com.example")
public class AppConfig {
// В этом классе можно определять дополнительные beans
@Bean
public DataSource dataSource() {
return new HikariDataSource();
}
}
Spring Boot автоматически
@SpringBootApplication // Включает @ComponentScan автоматически
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
// @SpringBootApplication эквивалентен:
// @Configuration + @EnableAutoConfiguration + @ComponentScan
Примеры различных фильтров
Только сервисы
@ComponentScan(
basePackages = "com.example",
includeFilters = @ComponentScan.Filter(
type = FilterType.ANNOTATION,
classes = Service.class
),
useDefaultFilters = false // отключить остальные
)
public class ServiceOnlyConfig {
}
// Найдёт: UserService, OrderService
// НЕ найдёт: UserController, UserRepository
Исключить Test классы
@ComponentScan(
basePackages = "com.example",
excludeFilters = @ComponentScan.Filter(
type = FilterType.REGEX,
pattern = ".*Test.*"
)
)
public class ProdConfig {
}
// НЕ найдёт: UserServiceTest, UserRepositoryTest
По названию (ASPECTJ)
@ComponentScan(
basePackages = "com.example",
includeFilters = @ComponentScan.Filter(
type = FilterType.ASPECTJ,
pattern = "com.example.service.*"
)
)
public class ServicePackageConfig {
}
// Найдёт только классы в пакете com.example.service
Порядок сканирования
1. @ComponentScan -> находит пакет (basePackages)
2. ClassPathScanningCandidateComponentProvider скарирует файлы
3. Для каждого .class файла:
a) Проверяет аннотации (@Component, @Service и т.д.)
b) Применяет фильтры (includeFilters, excludeFilters)
c) Если прошёл проверку → регистрирует BeanDefinition
4. Spring создаёт beans и инъектирует зависимости
Выводы
@ComponentScan сканирует на основании:
- Аннотаций (@Service, @Repository, @Controller и т.д.)
- Пакета (basePackages, basePackageClasses)
- Фильтров (includeFilters, excludeFilters)
- Типа фильтра (ANNOTATION, REGEX, ASPECTJ, CUSTOM)
Это основной механизм Spring для автоматической регистрации beans без явного определения каждого компонента. В Spring Boot @ComponentScan включена автоматически через @SpringBootApplication.