Короткий ответ
IoC (Inversion of Control) — принцип, по которому управление созданием и жизненным циклом объектов передаётся контейнеру. DI (Dependency Injection) — паттерн внедрения зависимостей и один из способов реализации IoC: контейнер сам предоставляет объекту его зависимости.
Как это работает подробнее
В Spring инверсию контроля реализует IoC-контейнер — базовый BeanFactory или расширенный ApplicationContext. Он создаёт бины, связывает их и управляет их временем жизни, поэтому приложение не вызывает new, а лишь описывает нужные ему объекты. Именно поэтому подход называется инверсией контроля: контроль над созданием объектов переходит от кода приложения к контейнеру.
- IoC шире, чем DI: IoC — общий принцип инверсии управления, а DI — конкретная техника, один из способов его реализации.
- Способы DI: внедрение через конструктор, через сеттер и напрямую в поле (field injection).
- Для запоминания: «Spring создаёт бин» — это IoC, а «Spring внедряет один бин в другой» — это DI.
Пример кода
UserService.java
@Service
public class UserService {
private final UserRepository repository;
public UserService(UserRepository repository) {
this.repository = repository;
}
}Что использовать на практике
- Предпочитайте внедрение через конструктор: объект создаётся полностью инициализированным и неизменяемым, его легко тестировать, передавая моки.
- Для опциональных зависимостей уместна сеттерная инъекция.
- Инъекцию в поле через
@Autowiredв продакшен-коде лучше избегать.
Подводные камни
- Не смешивайте IoC и DI: IoC — принцип, DI — лишь один из многих способов его реализации.
- Не путайте два контейнера Spring: ленивый
BeanFactoryи расширенныйApplicationContextс событиями, интернационализацией и автосозданием бинов.
Как отвечать на собеседовании
- Определите IoC как принцип, а DI как технику его реализации → покажите, что контейнер сам создаёт и связывает бины вместо
new→ назовите три способа внедрения (конструктор, сеттер, поле) → добавьте выгоду: слабая связанность, простота поддержки и тестирования.