Spring — IoC и бины
Spring — это в первую очередь IoC-контейнер. Вместо того чтобы код сам создавал свои зависимости через new, объектами (их называют бинами) управляет контейнер: он читает определения бинов, создаёт их, связывает друг с другом и хранит до конца жизни приложения. Ваш класс лишь объявляет, что ему нужно, — остальное делает ApplicationContext.
Из этой идеи вырастают два вопроса, которые задают почти на каждом Spring-интервью: что такое инверсия управления и внедрение зависимостей — и как контейнер решает, сколько экземпляров бина создать и как долго их держать (область видимости, scope). Второй вопрос почти всегда тянет за собой третий: потокобезопасен ли singleton по умолчанию (нет). Разбор — в слоях ниже.
Карта темы
- Инверсия управления и DI — контейнер, а не ваш код, создаёт и связывает объекты; внедрение через конструктор против внедрения в поле.
- Области видимости бинов —
singleton(по умолчанию),prototype,request/session; почему скоуп управляет числом экземпляров, а не потокобезопасностью.
Частые ошибки и ловушки
| Ошибка | Последствие |
|---|---|
Вызывать new для зависимости вместо внедрения | Объект вне контейнера: не получит своих бинов, прокси и конфигурации |
Внедрять в поле через @Autowired вместо конструктора | Зависимость нельзя сделать final, она скрыта и мешает тестам с new |
Считать скоуп по умолчанию prototype | По умолчанию singleton — один общий экземпляр на контейнер |
| Держать изменяемое состояние в singleton-бине | Гонка данных: конкурентные запросы делят один и тот же экземпляр |
| Ждать, что контейнер синхронизирует бины сам | Скоуп управляет числом экземпляров, а не потокобезопасностью |
Внедрить prototype в singleton и ждать новый экземпляр каждый раз | Зависимость резолвится один раз — при создании singleton |
Значение для собеседований
Spring спрашивают почти на каждом Java-бэкенд-интервью, но проверяют не знание аннотаций, а модель владения объектами: кто их создаёт, сколько их и как долго они живут.
Что обычно проверяют:
- Что такое инверсия управления и почему DI — её частный случай.
- Компромиссы внедрения через конструктор против внедрения в поле.
- Скоупы
singleton/prototype/request/sessionи что задаёт каждый. - Потокобезопасен ли
singletonпо умолчанию и что с этим делать. - Что происходит, когда
prototype-бин внедряют в singleton.
Типичный неверный ответ: «singleton потокобезопасен, ведь он один». Один экземпляр — это как раз источник проблемы: его делят все потоки, поэтому любое изменяемое поле становится разделяемым состоянием. Скоуп управляет числом экземпляров, а не синхронизацией; безопасность даёт отсутствие состояния (stateless) или явная синхронизация.