Как Spring знает, какие бины нужно подгрузить
Что проверяют
Понимаете ли вы, что Spring работает в два этапа: сначала собирает описания бинов из разных источников, потом создаёт объекты. Следом обычно спрашивают, откуда в Spring Boot берутся бины, которые вы не объявляли.
Как отвечать
Контейнер ApplicationContext при старте собирает BeanDefinition, то есть описания будущих объектов. Источники такие:
- сканирование компонентов:
@ComponentScanобходит пакет и его подпакеты и регистрирует классы с@Componentи производными от неё аннотациями:@Service,@Repository,@Controller,@Configuration; - Java-конфигурация: методы с
@Beanвнутри классов@Configuration, плюс@Import; - автоконфигурация Spring Boot:
@EnableAutoConfigurationчитает из зависимостей файлMETA-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.importsи подключает перечисленные там классы; - условия:
@Profile,@ConditionalOnClass,@ConditionalOnMissingBean,@ConditionalOnPropertyрешают, попадёт ли описание в контекст. ПоэтомуDataSourceпоявляется, только когда драйвер лежит в classpath и вы не объявили свой.
Разбор @Configuration и сканирование выполняет ConfigurationClassPostProcessor. Это BeanFactoryPostProcessor, он работает до создания объектов. Затем контейнер создаёт все синглтоны сразу, если они не помечены @Lazy, а prototype создаёт при каждом запросе. Зависимости разрешаются по типу, при нескольких кандидатах через @Qualifier, @Primary или имя.
@SpringBootApplication объединяет @SpringBootConfiguration, @EnableAutoConfiguration и @ComponentScan с пакетом главного класса в качестве корня. Отлаживать удобно через флаг --debug, который печатает отчёт по условиям, и эндпоинты Actuator /actuator/beans и /actuator/conditions.
Где спотыкаются
Считают, что Spring сканирует весь classpath. Класс в пакете выше или рядом с главным классом не найдётся, пока его не подключить явно.
Называют автоконфигурацию через spring.factories. Для автоконфигураций этот путь убрали в Spring Boot 3, актуален файл AutoConfiguration.imports.
Путают регистрацию с внедрением. @Autowired бин не «подгружает», он только просит готовый объект из контекста.