Что такое инверсия контроля
Что проверяют
Отличаете ли вы принцип от реализации: IoC, DI и принцип инверсии зависимостей из SOLID часто сваливают в одно. Для Java-разработчика следом почти гарантированно идёт Spring: как контейнер создаёт бины и почему рекомендуют внедрение через конструктор.
Как отвечать
Инверсия контроля это передача управления потоком выполнения внешнему коду. Не ваш код вызывает библиотеку, а фреймворк вызывает ваш код в нужный момент. Отсюда «принцип Голливуда»: не звоните нам, мы сами позвоним.
Формы IoC:
- Dependency Injection: объект не создаёт зависимости через
new, а получает их снаружи через конструктор, сеттер или поле; - Service Locator: объект сам запрашивает зависимость у реестра. Это тоже IoC, но зависимости спрятаны в теле методов, и тестировать сложнее;
- шаблонный метод и колбэки: сервлет-контейнер вызывает ваш
doGet, JUnit запускает методы с@Test, слушателя события вызывает фреймворк.
В Spring IoC-контейнер это ApplicationContext. Он читает конфигурацию (@Component со сканированием, @Configuration с методами @Bean), строит граф зависимостей, создаёт бины, по умолчанию singleton, внедряет зависимости и управляет жизненным циклом через @PostConstruct и @PreDestroy. Если у класса один конструктор, @Autowired на нём начиная со Spring 4.3 можно не писать.
Внедрение через конструктор предпочтительно: поля становятся final, объект нельзя получить недособранным, а в тесте его собирают руками без контекста. Кроме Spring, полезно знать Jakarta CDI, Guice и Dagger, который строит граф на этапе компиляции.
Где спотыкаются
Говорят, что IoC и DI одно и то же. DI лишь самая популярная форма IoC, а DIP вообще про направление зависимостей между модулями через абстракции.
Ставят @Autowired на приватные поля. Такой класс не собрать в юнит-тесте без рефлексии или контекста, а десяток полей не выдаёт, что класс делает слишком много.
Создают бин через new и удивляются NullPointerException: объект, созданный вручную, контейнеру неизвестен, и внедрять в него некому. Рядом живут циклические зависимости: со Spring Boot 2.6 они по умолчанию запрещены и роняют старт приложения.