Как Spring находит и создаёт бины (beans) для контекста приложения?

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

Ответ

Spring обнаруживает и регистрирует бины двумя основными способами: через сканирование компонентов и явное объявление.

1. Сканирование компонентов (Component Scanning)

Spring автоматически ищет классы, помеченные стереотипными аннотациями, в указанных пакетах.

  • Аннотации: @Component, @Service, @Repository, @Controller, @Configuration.
  • Область сканирования: По умолчанию сканируется пакет и все его подпакеты, где находится класс с @SpringBootApplication.
  • Настройка: Область сканирования можно изменить с помощью @ComponentScan.

Пример:

@SpringBootApplication
@ComponentScan({"com.example.main", "com.example.lib"})
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}
// Spring найдёт все @Component-классы в пакетах com.example.main и com.example.lib

2. Явное объявление в классах конфигурации

Бины можно объявить вручную в методах, помеченных @Bean, внутри классов с аннотацией @Configuration.

Пример:

@Configuration
public class AppConfig {
    @Bean
    public MyRepository myRepository() {
        // Здесь может быть сложная логика создания экземпляра
        return new MyRepositoryImpl();
    }

    @Bean
    @Primary // Указание основного бина при наличии нескольких того же типа
    public DataSource dataSource() {
        return new HikariDataSource();
    }
}

Процесс создания и управления

  1. Обнаружение: Spring находит классы-кандидаты.
  2. Создание: Инстанциирует бин (по умолчанию — синглтон).
  3. Наполнение (Population): Внедряет зависимости через @Autowired или конструктор.
  4. Инициализация: Вызывает методы с @PostConstruct или реализующие InitializingBean.
  5. Готовность: Бин помещается в ApplicationContext и становится доступным для инжекции.

Важно: Spring управляет полным жизненным циклом бина, включая его уничтожение (вызов @PreDestroy).