Які етапи є у Bean lifecycle?
BPP (BeanPostProcessor) — механізм Spring для зміни бінів. Ключові BPP:
🟢 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
- Конструктор → лише присвоєння полів
- @PostConstruct → валідація, легка ініціалізація
- @PreDestroy → очищення ресурсів
- Prototype → самі чистіть
- ContextRefreshedEvent → коли все готово
- 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]]