Сталкивались ли с IoC контейнером?
Что проверяют
Отличаете ли вы принцип от инструмента: IoC это идея, внедрение зависимостей это способ, контейнер это то, что её реализует. Вопрос открывающий, за ним почти всегда идут скоупы бинов, циклические зависимости и прокси, поэтому короткое «да, работал со Spring» только запускает цепочку уточнений.
Как отвечать
Начните с сути: объект не создаёт свои зависимости сам, а получает их снаружи, и за создание отвечает контейнер. В Spring это ApplicationContext: он читает конфигурацию (@Component со сканированием пакетов, @Configuration с методами @Bean, исторически XML), строит граф бинов, разрешает зависимости и управляет жизненным циклом, включая @PostConstruct и @PreDestroy.
Дальше покажите практику:
- внедрение через конструктор как основной вариант: поля объявляются
final, объект не существует в полусобранном виде, класс тестируется обычнымnewбез контейнера; - скоупы:
singletonпо умолчанию,prototype, веб-скоупы запроса и сессии; - выбор среди нескольких кандидатов:
@Primary,@Qualifier, внедрение всей коллекции реализаций интерфейса; - контейнер отдаёт не сам бин, а прокси, и на этом держатся
@Transactional,@Async, кэширование.
Хорошо добавить, зачем это нужно вам: подмена реализации в тестах и разделение слоёв даются почти бесплатно.
Где спотыкаются
Ставят знак равенства между IoC и Spring. Принцип шире: есть CDI, Guice, Dagger, а сборка зависимостей руками в конструкторах это тоже инверсия управления, просто без контейнера.
Внедряют через @Autowired на поле. Зависимости становятся невидимыми снаружи, поле нельзя сделать final, тест требует рефлексии или поднятия контекста. Циклическая зависимость на конструкторах честно падает при старте, а на полях тихо живёт до странного бага.
Забывают про прокси. Вызов метода с @Transactional из соседнего метода того же бина идёт мимо прокси, и транзакции просто нет. Рядом вторая ловушка: бин со скоупом singleton и изменяемым полем разделяется всеми потоками.