Питання 7 · Розділ 5

Які етапи є у Bean lifecycle?

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. Що таке Bean scope]]