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

Ответ

Бин может не быть создан и зарегистрирован в 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(); } // Два бина одного типа!
}

Ответ 18+ 🔞

А, слушай, вот эта вся история с бинами в Спринге — это ж классика, блядь! Чувак сидит, ждёт, а его бин как в воду канул, нихуя в контексте нет! Ну, давай разбираться, как так выходит, что твой класс остаётся за бортом, как Муму в том озере, ёпта.

Первая причина — ты его просто не позвал, балбес! Ну серьёзно, как Герасим, который немой, твой класс молчит, и Спринг его не слышит. Не повесил ты на него волшебную табличку: @Component, @Service, @Repository или @Controller. Либо не прописал его как @Bean в конфигурационном классе. Без этого — он для фреймворка просто кусок кода, как деревянный Буратино до превращения в человека.

Вторая — он в другом лесу, а ты ищешь не там! Спринг сканирует пакеты, как собака ищет кость. Если твой класс сидит в пакете com.example.other, а сканирование настроено только на com.example.main, то он его просто не увидит, блядь! По умолчанию-то сканируется пакет от класса с @SpringBootApplication и всё вниз, но если ты накосячил с ручной настройкой — пиши пропало.

Третья — не сошлись звёзды, условия не выполнились! Ты мог навесить @ConditionalOnProperty, мол, создавайся, только если в настройках some.property=true. А в настройках — false! Или @ConditionalOnClass ждёт какой-то библиотеки, а её нет в classpath. Короче, условия не прошёл — сиди, мудак, в сторонке.

Четвёртая — друзей нет, одному скучно! Твой бин заявил: «Я не могу жить без этого репозитория!» — через @Autowired. А этот репозиторий сам-то не бин! Его нет в контексте. Вот и получается, как Герасим без Муму — нихуя не работает. Или, что ещё веселее, у вас циклическая зависимость: Service ждёт Repository, а Repository ждёт Service. И стоят, уставившись друг на друга, как дураки, пока контекст не рухнет с матерной ошибкой.

Пятая — бардак и пиздец! А, это моё любимое! Создал ты два бина одного и того же типа DataSource. Spring смотрит и офигевает: «Какой из них, блядь, внедрять-то?». И начинает орать NoUniqueBeanDefinitionException. Не указал @Primary на главном, не расставил @Qualifier — получай проблемы, как в той басне про лебедя, рака и щуку.

И шестая — сам себя похоронил! В конструкторе бина или в методе с @PostConstruct вылетает исключение. Spring пытается его создать, а там — бах! — NullPointerException или ещё какая хуйня. Бин умирает, даже не родившись. Накрылся медным тазом, короче.

Вот, смотри, примеры, как можно накосячить, прям как в том анекдоте:

// ПРИЧИНА 1: Нет аннотации - бин не будет создан. Вообще. Тишина.
public class MyService {
    // Просто класс. Как столб. Ни хуя не происходит.
}

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

// ПРИЧИНА 5: Конфликт типов. Spring просто охуеет от выбора.
@Configuration
public class AppConfig {
    @Bean
    public DataSource dataSource1() { return new HikariDataSource(); }
    @Bean
    public DataSource dataSource2() { return new HikariDataSource(); } // Два одинаковых! Ну ты даёшь!
}

Короче, чувак, если бин не создаётся — иди по этому списку, как по чек-листу. Где-то ты обязательно наступил в это говно. Удачи, ебать!