Как Spring создает бин на основе аннотации @Bean в конфигурационном классе?

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

Ответ

Spring создает и регистрирует бин при обработке метода, помеченного @Bean, внутри класса с аннотацией @Configuration.

Процесс создания:

  1. Обнаружение: Контейнер Spring находит все классы, помеченные @Configuration.
  2. Обработка методов @Bean: Для каждого метода с аннотацией @Bean Spring вызывает его, чтобы получить объект.
  3. Проксирование (CGLIB): Классы @Configuration проксируются по умолчанию. Это гарантирует, что вызовы методов @Bean внутри того же конфигурационного класса будут перенаправлены контейнеру, что позволяет сохранить семантику синглтона (метод будет вызван только один раз, а результат закэширован).
  4. Регистрация: Возвращаемый объект регистрируется в контексте приложения как бин.

Пример и детали:

@Configuration
public class AppConfig {

    @Bean // Имя бина по умолчанию — 'myService'
    public MyService myService() {
        // Этот метод будет вызван Spring'ом ровно один раз
        return new MyServiceImpl();
    }

    @Bean(name = "customDataSource") // Явное указание имени бина
    @Primary // Помечает бин как предпочтительный при внедрении по типу
    public DataSource dataSource() {
        return new HikariDataSource();
    }

    @Bean
    @Scope("prototype") // Область видимости — новый экземпляр при каждом запросе
    public TransactionalService transactionalService() {
        return new TransactionalService();
    }
}

Важные аспекты:

  • Жизненный цикл: К бинам, созданным через @Bean, применяются callback-методы жизненного цикла (@PostConstruct, @PreDestroy, интерфейсы InitializingBean, DisposableBean).
  • Внедрение зависимостей: Параметры метода @Bean автоматически рассматриваются как зависимости для внедрения.
    @Bean
    public OrderProcessor orderProcessor(MyService service, DataSource dataSource) {
    return new OrderProcessor(service, dataSource);
    }
  • Отличие от @Component: @Bean позволяет регистрировать как экземпляры собственных классов, так и экземпляры сторонних библиотек, код которых вы не можете аннотировать.