Вопрос 7 · Раздел 5

Какие этапы жизненного цикла Bean?

BPP (BeanPostProcessor) — механизм Spring для изменения бинов. Ключевые BPP:

Версии по языкам: English Russian Ukrainian

🟢 Junior Level

Этапы создания бина:

1. Конструктор → объект создан
2. @Autowired → зависимости внедрены
3. @PostConstruct → инициализация
4. Готов к работе
5. @PreDestroy → очистка при удалении
@Service
public class MyService {
    
    private final Repo repo;
    
    // 1. Конструктор
    public MyService(Repo repo) {
        this.repo = repo;
    }
    
    // 2. @Autowired уже сработал (через конструктор)
    
    // 3. Инициализация
    @PostConstruct
    public void init() {
        System.out.println("Bean готов!");
    }
    
    // 5. Очистка
    @PreDestroy
    public void cleanup() {
        System.out.println("Bean удаляется");
    }
}

🟡 Middle Level

Этот вопрос детализирует этапы из файла [[6. Что такое Bean Lifecycle]]. Если тот файл объясняет ЗАЧЕМ, то этот — КАК именно (12 шагов).

Подробный порядок

1. Instantiation (конструктор)
2. Populate Properties (@Autowired поля/сеттеры)
3. Aware Interfaces
   → BeanNameAware.setBeanName()
   → BeanFactoryAware.setBeanFactory()
   → ApplicationContextAware.setApplicationContext()
4. BeanPostProcessor.postProcessBeforeInitialization()
5. @PostConstruct
6. InitializingBean.afterPropertiesSet()
7. init-method (@Bean(initMethod="init"))
8. BeanPostProcessor.postProcessAfterInitialization() ← Proxy!
9. READY
10. @PreDestroy
11. DisposableBean.destroy()
12. destroy-method

Singleton vs Prototype

// Singleton:
// → Все этапы 1-12
// → Уничтожается при закрытии контекста

// Prototype:
// → Только этапы 1-9
// → @PreDestroy НЕ вызывается автоматически. Spring не отслеживает их уничтожение. Если нужно — вызывайте cleanup вручную или используйте `ConfigurableBeanFactory.registerDestructionCallback()`.

ContextRefreshedEvent

// Когда ВСЕ бины созданы и инициализированы:
@EventListener(ContextRefreshedEvent.class)
public void onApplicationReady() {
    // Все прокси созданы, все бины готовы
    // Можно вызывать @Transactional методы!
}

🔴 Senior Level

Instantiation vs Initialization

Instantiation:
  → new Service() через рефлексию
  → Объект существует в Heap
  
Initialization:
  → Внедрение зависимостей
  → @PostConstruct
  → Proxy creation
  
→ В конструкторе зависимости ещё не внедрены (кроме Constructor Injection)

BPP цепочка

BPP (BeanPostProcessor) — механизм Spring для изменения бинов. Ключевые BPP:

  • CommonAnnotationBeanPostProcessor — обрабатывает @PostConstruct/@PreDestroy
  • AutowiredAnnotationBeanPostProcessor — обрабатывает @Autowired
  • AnnotationAwareAspectJAutoProxyCreator — создаёт прокси для @Transactional, @Async
Много BPP выполняются последовательно:
  1. CommonAnnotationBeanPostProcessor → @PostConstruct
  2. AutowiredAnnotationBeanPostProcessor → @Autowired
  3. AnnotationAwareAspectJAutoProxyCreator → Proxy
  
→ Каждый может изменить или заменить бин
→ Порядок важен! → @Order

Ранняя инициализация BPP

// Если ваш BPP зависит от MyService:
// → MyService создаётся РАНЬШЕ остальных BPP
// → MyService может не получить прокси!

// Почему: BPP, создающие прокси (например, AnnotationAwareAspectJAutoProxyCreator для @Transactional), ещё не зарегистрированы. MyService создаётся «голым», без прокси-обёртки. Решение: не инжектируйте бины в BPP — используйте ObjectProvider или ApplicationContext.getBean() с осторожностью.

// Решение: @Lazy или независимые BPP

Production Experience

Реальный сценарий: BPP не получил прокси

  • Кастомный BPP зависел от DataSource
  • DataSource создался раньше → без транзакций
  • Решение: @Lazy зависимость в BPP
  • Результат: прокси создался корректно

Best Practices

  1. Конструктор → только присвоение полей
  2. @PostConstruct → валидация, лёгкая инициализация
  3. @PreDestroy → очистка ресурсов
  4. Prototype → сами чистите
  5. ContextRefreshedEvent → когда всё готово
  6. BPP dependencies → @Lazy

Резюме для Senior

  • 12 этапов → от конструктора до destroy
  • Proxy создаётся на этапе 8 (после @PostConstruct)
  • Prototype → нет этапов 10-12
  • BPP ordering → важно через @Order
  • ContextRefreshedEvent → все бины готовы
  • Ранняя инициализация → может сломать прокси

🎯 Шпаргалка для интервью

Обязательно знать:

  • 12 этапов: Instantiation → Populate Properties → Aware Interfaces → BPP Before → @PostConstruct → afterPropertiesSet → init-method → BPP After (Proxy!) → Ready → @PreDestroy → DisposableBean → destroy-method
  • Aware-интерфейсы: BeanNameAware, BeanFactoryAware, ApplicationContextAware — бин получает информацию от контейнера
  • Proxy создаётся на этапе 8 — BPP.postProcessAfterInitialization(), после @PostConstruct
  • Singleton проходит все 12 этапов, Prototype — только 1-9 (нет destroy)
  • ContextRefreshedEvent — публикуется когда ВСЕ бины и прокси созданы, можно вызывать @Transactional методы
  • Ранняя инициализация BPP: если BPP зависит от бина, тот создаётся раньше остальных BPP и может не получить прокси
  • BPP ordering через @Order — порядок важен, каждый BPP может заменить бин

Частые уточняющие вопросы:

  • В чём разница между Instantiation и Initialization? Instantiation = new через рефлексию (объект существует). Initialization = DI, @PostConstruct, Proxy creation.
  • Какие Aware-интерфейсы вы знаете? BeanNameAware (имя бина), BeanFactoryAware (фабрика), ApplicationContextAware (контекст).
  • Почему кастомный BPP может не получить прокси? Если бин создаётся раньше BPP, создающего прокси — бин остаётся «голым».
  • Как управлять порядком BPP? Аннотация @Order — меньшее значение = раньше выполнение.

Красные флаги (НЕ говорить):

  • «В конструкторе все зависимости уже внедрены» (кроме Constructor Injection — зависимости ещё NULL)
  • «Prototype бины вызывают @PreDestroy» (нет, Spring не отслеживает их уничтожение)
  • «Порядок BPP не важен» (критически важен — первый BPP может заменить бин для второго)
  • «Можно тянуть любые зависимости в BPP» (это вызывает раннюю инициализацию и ломает прокси)

Связанные темы:

  • [[6. Что такое Bean Lifecycle]]
  • [[8. Что такое BeanPostProcessor]]
  • [[9. Что делают методы с аннотацией @PostConstruct и @PreDestroy]]
  • [[4. Что такое Bean в Spring]]
  • [[10. Что такое scope Bean]]