IoC и Dependency Injection

Базовый Spring
≈ 2 мин чтения

Зависимость не обязательно создавать самому

Представь сервис, который отправляет уведомление. Ему нужен объект для отправки сообщения. Самый прямой вариант — создать его внутри сервиса через new. Но тогда сервис сам решает, какую реализацию использовать, и оказывается жёстко с ней связан.

class NotificationService {
    private final MessageSender sender;

    NotificationService(MessageSender sender) {
        this.sender = sender;
    }

    void notifyUser(String message) {
        sender.send(message);
    }
}

Здесь NotificationService не создаёт отправителя. Он просто объявляет: «для работы мне нужен MessageSender». Готовый объект передаётся снаружи через конструктор. Это и есть Dependency Injection — внедрение зависимости.

Где здесь IoC

Inversion of Control — идея шире. Код класса больше не контролирует весь процесс создания и связывания объектов. Эту часть управления получает внешний механизм — в Spring это контейнер. Он знает, какие объекты доступны, какие зависимости им нужны и как собрать из них готовую систему.

DI — один из главных способов реализовать IoC. Вместо цепочки из десятков ручных new контейнер создаёт объекты сам и передаёт им нужные зависимости.

Предпочитай зависимости через конструктор. Так обязательные зависимости видны прямо из сигнатуры класса, объект нельзя случайно создать в неполном состоянии, а сам класс проще использовать и тестировать без Spring.

Что меняется в мышлении

В Spring-приложении полезно задавать не вопрос «где мне создать этот объект?», а вопрос «какой объект мне нужен для работы?». Создание и связывание постепенно переносится из бизнес-кода в конфигурацию контейнера. На следующих страницах мы увидим, где этот контейнер живёт и какими объектами он управляет.