Вопрос 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]]
  • [[8. Что такое BeanPostProcessor]]
  • [[9. Что делают методы с аннотацией @PostConstruct и @PreDestroy]]
  • [[4. Что такое Bean в Spring]]
  • [[10. Что такое scope Bean]]