← Назад к списку
ТехническаяJava и KotlinMiddle

Что такое IoC и DI в Spring? Опишите жизненный цикл бина и основные скоупы.

Короткий ответ

  • IoC — контейнер сам создаёт объекты и управляет их жизнью
  • DI — зависимости внедряются извне: конструктор, сеттер, поле
  • Конструкторное внедрение — рекомендуемое: иммутабельность и явные зависимости
  • Цикл: создание → внедрение → BeanPostProcessor → @PostConstruct → работа → @PreDestroy
  • Скоупы: singleton (по умолчанию), prototype, request, session
  • Прокси и AOP навешиваются на этапе пост-процессоров

Spring-контейнер создаёт бины, внедряет зависимости и проводит их через управляемый жизненный цикл с точками расширения.

Как сказать вслух

пример ответа

Inversion of Control означает, что не я создаю объекты через new, а контейнер: он читает конфигурацию, строит бины и соединяет их между собой. Dependency Injection — способ передать зависимости, лучше всего через конструктор. Жизненный цикл такой: бин создаётся, в него внедряются зависимости, отрабатывают пост-процессоры — именно там появляются прокси для транзакций — потом метод инициализации, и при остановке контекста метод destroy. По умолчанию каждый бин — синглтон на контекст.

Подробный ответ

Основной ответ

IoC-контейнер (ApplicationContext) по конфигурации (@Component-сканирование, @Bean-методы) строит BeanDefinition, затем создаёт бины: инстанцирование → внедрение зависимостей → Aware-интерфейсы → BeanPostProcessor.postProcessBeforeInitialization → @PostConstruct/afterPropertiesSet → postProcessAfterInitialization (здесь оборачивание в AOP-прокси для @Transactional, @Async) → бин готов. При закрытии контекста — @PreDestroy. Скоупы: singleton — один экземпляр на контекст (по умолчанию), prototype — новый на каждый запрос к контейнеру (контейнер не управляет его уничтожением), web-скоупы request/session. DI через конструктор предпочтительнее полевого @Autowired: зависимости видны, можно сделать поля final, легко тестировать без Spring. Циклические зависимости конструкторов контейнер разрешить не может — это сигнал к рефакторингу.

Ключевые моменты

  • BeanPostProcessor. Точка расширения, где рождаются прокси; поэтому self-invocation мимо прокси ломает @Transactional.
  • Конструкторная инъекция. final-поля, явный контракт, простое юнит-тестирование; полевая инъекция затрудняет тесты.
  • Скоупы. singleton — состояние шарится между потоками, поэтому бины должны быть stateless; prototype Spring не уничтожает.
  • Инициализация. @PostConstruct — после внедрения всех зависимостей; конструктор для этого не годится.

Практический контекст

Это основа любого Java-бэкенд-интервью со Spring. Практические следствия: нельзя хранить изменяемое состояние в синглтоне, тяжёлую инициализацию переносить в @PostConstruct, а циклические зависимости лечить выделением третьего бина. Интервьюер любит связку вопросов: «почему конструкторная инъекция», «когда создаётся прокси», «что будет с prototype внутри singleton».

Частые ошибки

  • Путают IoC (принцип) и DI (механизм его реализации)
  • Хранят состояние запроса в singleton-бине и получают гонки
  • Ожидают @PreDestroy у prototype-бинов — контейнер их не уничтожает

ИП Кочкин Алексей Сергеевич · ИНН 390509026279 · ОГРНИП 325390000030973 · jiniys2005@yandex.ru