Каковы основные причины, по которым Spring-бин может не создаться в контексте приложения?

«Каковы основные причины, по которым Spring-бин может не создаться в контексте приложения?» — вопрос из категории Spring, который задают на 10% собеседований Java Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Бин может не быть создан и зарегистрирован в Spring-контексте по нескольким причинам:

1. Отсутствие стереотипной аннотации или конфигурации:

  • Класс не помечен аннотацией @Component, @Service, @Repository, @Controller или не объявлен как @Bean в классе с @Configuration.

2. Неправильное сканирование компонентов:

  • Пакет, содержащий класс, не попадает в область сканирования, заданную @ComponentScan. По умолчанию сканируется пакет и его подпакеты от класса с @SpringBootApplication.

3. Неудовлетворенные условия создания:

  • Условие, заданное аннотацией @Conditional, @ConditionalOnClass, @ConditionalOnProperty и т.д., не выполняется.

4. Проблемы с внедрением зависимостей:

  • У бина есть зависимость, помеченная @Autowired (или используется конструктор), но эта зависимость сама не является бином (не найдена в контексте).
  • Возникла циклическая зависимость (circular dependency), если разрешение таких зависимостей не настроено.

5. Конфликты и исключения:

  • Несколько бинов одного типа, и Spring не может выбрать один для автоматического связывания (NoUniqueBeanDefinitionException), при этом не указан @Primary или @Qualifier.
  • В конструкторе или методе инициализации бина выбрасывается необработанное исключение.

Пример проблемного кода:

// ПРИЧИНА 1: Нет аннотации - бин не будет создан.
public class MyService { }

// ПРИЧИНА 4: Зависимость не найдена - создание бина упадет с исключением.
@Service
public class UserService {
    @Autowired
    private NonExistentRepository repo; // Этот класс не является бином!
}

// ПРИЧИНА 5: Конфликт типов.
@Configuration
public class AppConfig {
    @Bean
    public DataSource dataSource1() { return new HikariDataSource(); }
    @Bean
    public DataSource dataSource2() { return new HikariDataSource(); } // Два бина одного типа!
}