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

Що таке Bean Lifecycle?

Три кеші для вирішення циклічних залежностей:

Мовні версії: English Russian Ukrainian

🟢 Junior Level

Bean Lifecycle — це всі етапи життя біна від створення до видалення.

Навіщо знати lifecycle: (1) ініціалізувати ресурси у правильний момент, (2) розуміти, чому @Transactional не працює з @PostConstruct, (3) правильно очищати ресурси, (4) вирішувати циклічні залежності.

Проста аналогія: Життя людини: народження → дорослішання → робота → пенсія.

Основні етапи:

1. Створення (конструктор)
2. Впровадження залежностей
3. Ініціалізація (@PostConstruct)
4. Робота (готовий до використання)
5. Знищення (@PreDestroy)

У Spring 6 / Boot 3: використовуйте jakarta.annotation.PostConstruct замість javax.annotation.PostConstruct.

@Service
public class MyBean {

    public MyBean() {
        // 1. Створення
    }

    @PostConstruct
    public void init() {
        // 3. Ініціалізація
    }

    @PreDestroy
    public void cleanup() {
        // 5. Знищення
    }
}

🟡 Middle Level

Фази життєвого циклу

1. BeanDefinition → мета-інформація
2. Instantiation → конструктор
3. Populate Properties → @Autowired
4. Aware Interfaces → setBeanName, setBeanFactory
5. @PostConstruct → ініціалізація
6. Ready → бін готовий
7. @PreDestroy → очищення

Singleton vs Prototype

Етап Singleton Prototype
Створення Один раз Щоразу при запиті
Ініціалізація ✅ Викликається ✅ Викликається
Знищення ✅ Викликається ❌ НЕ викликається!
// Prototype: ви самі повинні очистити ресурси!
PrototypeBean bean = context.getBean(PrototypeBean.class);
try {
    // використання
} finally {
    bean.cleanup();  // Вручну!
}

SmartLifecycle

// Для запуску/зупинки компонентів
@Component
public class MyService implements SmartLifecycle {
    public void start() { /* Запуск після ініціалізації всіх бінів */ }
    public void stop() { /* Зупинка при shutdown */ }
    public boolean isRunning() { return running; }
    public int getPhase() { return 0; }  // Порядок запуску
}

🔴 Senior Level

Коли НЕ використовувати @PostConstruct

  1. Важка ініціалізація — блокує запуск всього контексту. Використовуйте SmartLifecycle або @EventListener(ContextRefreshedEvent)
  2. Виклик @Transactional методів — проксі ще не створено, транзакція не працює
  3. Операції з retry — якщо ініціалізація може впасти (немає підключення до БД), використовуйте SmartLifecycle з повторними спробами

Трьохрівневий кеш і цикли

Три кеші для вирішення циклічних залежностей:

  1. singletonObjects — готові біни (повністю ініціалізовані)
  2. earlySingletonObjects — створені, але не ініціалізовані (для розриву циклів)
  3. singletonFactories — фабрики, що створюють ранні посилання
DefaultListableBeanFactory кеші:
  1. singletonObjects → готові біни
  2. earlySingletonObjects → створені, але не ініціалізовані
  3. singletonFactories → фабрики для отримання раннього посилання

→ Вирішує цикли для Field/Setter Injection
→ Constructor Injection не може використовувати кеш 3

Proxy Creation точка

BPP.postProcessAfterInitialization():
  → Тут створюються AOP Proxy
  → Бін замінюється на Proxy в контейнері

@PostConstruct викликається ДО проксі!
  → Виклик @Transactional методу з @PostConstruct НЕ спрацює
  → Рішення: ApplicationListener<ContextRefreshedEvent>

BPP Ordering

// Порядок BPP важливий!
@Order(1)
public class FirstBPP implements BeanPostProcessor { }

@Order(2)
public class SecondBPP implements BeanPostProcessor { }

 FirstBPP виконається раніше

Production Experience

Реальний сценарій: @PostConstruct + @Transactional

@PostConstruct
public void init() {
    loadData();  // @Transactional → НЕ працює!
}

// Причина: проксі ще не створено
// Рішення:
@EventListener(ContextRefreshedEvent.class)
public void init() {
    loadData();  // Тепер проксі є → транзакція працює
}

Best Practices

  1. @PostConstruct → валідація, ініціалізація
  2. @PreDestroy → очищення ресурсів
  3. Prototype → самі чистіть ресурси
  4. SmartLifecycle → порядок запуску
  5. @PostConstruct → немає проксі ще!
  6. BPP order → управляйте через @Order

Резюме для Senior

  • Instantiation ≠ Initialization
  • Трьохрівневий кеш → вирішення циклів
  • Proxy створюється ПІСЛЯ @PostConstruct
  • Prototype → @PreDestroy НЕ викликається
  • SmartLifecycle → старт/стоп компонентів
  • ContextRefreshedEvent → коли все готово

🎯 Шпаргалка для співбесіди

Обов’язково знати:

  • Bean Lifecycle: створення → впровадження залежностей → ініціалізація (@PostConstruct) → готовий → знищення (@PreDestroy)
  • Lifecycle потрібен для: ініціалізації ресурсів, розуміння чому @Transactional не працює з @PostConstruct, очищення ресурсів, вирішення циклів
  • Singleton: всі етапи 1-12, @PreDestroy викликається при закритті контексту
  • Prototype: лише створення та ініціалізація, @PreDestroy НЕ викликається — чистіть вручну
  • Трьохрівневий кеш (singletonObjects, earlySingletonObjects, singletonFactories) вирішує циклічні залежності
  • Proxy створюється ПІСЛЯ @PostConstruct — виклик @Transactional методу з @PostConstruct не спрацює
  • SmartLifecycle — для запуску/зупинки компонентів з порядком (getPhase())
  • У Spring 6 / Boot 3: jakarta.annotation.PostConstruct замість javax.annotation

Часті уточнюючі запитання:

  • Чому @Transactional не працює з @PostConstruct? Проксі створюється після @PostConstruct, виклик йде до оригінального об’єкта.
  • Як вирішити проблему з транзакцією при ініціалізації? @EventListener(ContextRefreshedEvent.class) — всі проксі вже створені.
  • Чому Prototype не викликає @PreDestroy? Spring не відстежує знищення prototype-бінів — викликайте cleanup вручну.
  • Що таке трьохрівневий кеш? Кеш готових бінів, ранніх посилань і фабрик — вирішує цикли для Field/Setter Injection.

Червоні прапорці (НЕ говорити):

  • «@PostConstruct — місце для важкої ініціалізації» (блокує старт контексту, використовуйте SmartLifecycle)
  • «Prototype біни очищуються автоматично» (@PreDestroy НЕ викликається для Prototype)
  • «Всі scope працюють однаково з lifecycle» (Prototype пропускає етапи знищення)
  • «@PostConstruct і ініціалізація — одне й те саме» (Instantiation ≠ Initialization)

Пов’язані теми:

  • [[7. Які етапи є у Bean lifecycle]]
  • [[8. Що таке BeanPostProcessor]]
  • [[9. Що роблять методи з анотаціями @PostConstruct та @PreDestroy]]
  • [[4. Що таке Bean в Spring]]
  • [[10. Що таке Bean scope]]