Введение в внедрение зависимостей.

Внедрение зависимостей - это шаблон проектирования, который делегирует управление зависимостями фреймворку. Spring Framework инициализирует и внедрит необходимые объекты для других объектов.

Как весенний официальный документ:

IoC также известен как внедрение зависимостей (DI). Это процесс, при котором объекты определяют свои зависимости (то есть другие объекты, с которыми они работают) только с помощью аргументов конструктора, аргументов фабричного метода или свойств, которые устанавливаются для экземпляра объекта после его создания или возврата из фабричного метода. . Затем контейнер внедряет эти зависимости при создании bean-компонента. По сути, этот процесс является инверсией (отсюда и название «инверсия управления») самого bean-компонента, управляющего созданием экземпляра или расположением его зависимостей с помощью прямого построения классов или такого механизма, как шаблон Service Locator.

Https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#beans-introduction

Подробнее: https://martinfowler.com/articles/injection.html

Что такое автоподводка

Автосоединение - это процесс поиска потенциального соответствия объекта, требующего зависимости, и внедрения его в целевой объект. Этот проект в основном выполняется AutowiredAnnotationBeanPostProcessor и Java Reflection API.



Spring будет полагаться на какое-то соглашение или обнаружение для аннотации Autowired для обработки зависимости внедрения.

Помимо Autowired, Spring также поддерживает JSR-330, что означает, что мы можем использовать как javax.inject.Inject, так и Autowired. Я предпочитаю Autowired, потому что он включает семантику обязательного и необязательного.

Полевая инъекция

Приведем пример с контроллером и службой. Контроллеру требуется услуга для обработки данных.

Следуя приведенному выше коду, когда мы запускаем приложение и отправляем запрос на получение на сервер, ожидаем ответа, как показано ниже.

Мы не использовали ключевое слово new для запуска demoService внутри DemoControler, но demoService не было нулевым, верно? Вот что сделала для нас весна.

Теперь представьте, что у нас есть еще одна реализация интерфейса DemoService. Для этого нам нужно создать новый конкретный класс. как показано ниже. Я назвал его DemoServiceAlphaImpl.

После добавления более реализованного класса без изменения DemoController приложение не смогло запуститься со следующим сообщением ниже.

***************************
APPLICATION FAILED TO START
***************************
Description:
Field demoService in com.programmingsharing.springboottopics.fieldinjection.DemoController required a single bean, but 2 were found:
 - demoServiceAlphaImpl: defined in file [I:\Blogging\spring-boot-topics\target\classes\com\programmingsharing\springboottopics\fieldinjection\DemoServiceAlphaImpl.class]
 - demoServiceImpl: defined in file [I:\Blogging\spring-boot-topics\target\classes\com\programmingsharing\springboottopics\fieldinjection\DemoServiceImpl.class]

Причина уже указана в сообщении, Spring обнаружил два согласованных bean-компонента (объекта), но не знает, какой из них следует внедрить. Поэтому он выдает сообщение.

Два найденных bean-компонента - это demoServiceImpl, а demoServiceAlphaImpl на самом деле является верблюжьим регистром имени реализованных классов. Я знаю два известных мне решения.

  • используйте @Qualifier(“<bean name>”), например: @Qualifier(“demoServiceAlphaImpl”)

  • измените имя поля, чтобы оно соответствовало найденному bean-name.

Внедрение конструктора

Другой способ внедрить зависимость в Spring - использовать конструктор. Конструктор по умолчанию (без аргументов) не может работать (очевидно). Если конструкторов несколько, Spring может выбрать только один конструктор для инициализации и внедрения зависимостей.

Как весенние документы:

Только один конструктор любого заданного класса bean-компонента может объявить эту аннотацию с обязательным атрибутом, установленным в true, указывая, что конструктор автоматически подключается при использовании в качестве bean-компонента Spring. Более того, если для обязательного атрибута установлено значение true, только один конструктор может быть аннотирован с помощью @Autowired. Если несколько необязательных конструкторов объявляют аннотацию, они будут рассматриваться как кандидаты для автоматического подключения. Будет выбран конструктор с наибольшим количеством зависимостей, которые могут быть удовлетворены путем сопоставления bean-компонентов в контейнере Spring. Если ни один из кандидатов не может быть удовлетворен, будет использоваться основной конструктор / конструктор по умолчанию (если он есть). Точно так же, если класс объявляет несколько конструкторов, но ни один из них не аннотирован @Autowired, тогда будет использоваться основной конструктор / конструктор по умолчанию (если он есть). Если класс для начала объявляет только один конструктор, он всегда будет использоваться, даже если он не аннотирован. Аннотированный конструктор не обязательно должен быть общедоступным.

Следуйте приведенному ниже фрагменту кода, чтобы применить конструктор inject. Spring будет использовать объявленный конструктор для инициализации объекта контроллера с помощью demoServiceAImpl bean (предыдущий раздел).

Объедините внедрение конструктора с внедрением поля

В случае многих сервисов мы можем комбинировать внедрение поля и внедрение конструктора. Нравится:

Несколько конструкторов

В случае, если класс, управляемый компонентом, имеет несколько конструкторов, всегда используется конструктор, помеченный @Autowired или @Autowired(required = true), и только один конструктор может быть помечен @Autowired(required = true).

Если все конструкторы помечены как @Autowired(required = false), как указано выше, Spring будет искать все потенциально совпадающие bean-компоненты и выбирать подходящий конструктор.

  • Если нет bean demoServiceAImpl и demoServiceB, выбирается отсутствие аргумента.
  • Если найден единственный bean demoServiceAImpl, выбирается второй конструктор.
  • Если обнаружены и demoServiceAImpl, и demoServiceB, выбирается конструктор с двумя аргументами.

Преимущества использования внедрения конструктора

С помощью внедрения конструктора мы можем написать код для проверки типа экземпляра внедренного bean-компонента или делать все, что мы можем делать с кодированием. например, ведение журнала, выброс исключения и т. д.

Недостаток использования инъекции конструктора.

Требовалось много конструкторов для внедрения в каком-то особом случае. Иногда необходимый конструктор с множеством аргументов выглядит довольно некрасиво.

Инъекция сеттера

Внедрение установщика аналогично внедрению конструктора, но здесь мы используем метод установщика для внедрения компонента.

Для использования инъекции сеттера мы можем применить бизнес-логику во время инъекции.

Впрыск в методе конфигурации

Вы использовали класс конфигурации для настройки безопасности, ресурсов или cron? Надеюсь, что вы это сделали.

В приведенном выше примере демонстрируется конфигурация cors, corsRegistry автоматически вводится Spring.

Внедрение списка

Представьте, что нам нужно создать приложение для синтаксического анализа, которое может анализировать строковое значение для целевого объекта, такого как Date, DateTime, Integer, Boolean,… При непредсказуемом вводе мы не знаем, какой синтаксический анализатор внедрить. Кроме того, приложение требует наличия возможности добавлять дополнительные анализаторы без изменения существующей службы синтаксического анализатора.

Идея состоит в том, чтобы добавить все компоненты синтаксического анализатора в список. Когда начнем синтаксический анализ ввода, мы обнаружим синтаксический анализатор из списка синтаксических анализаторов.

Резюме

Прочитав этот раздел, мы познакомились с тем, что такое внедрение зависимостей, типами внедрения: внедрение поля, внедрение конструктора, внедрение установщика, внедрение метода конфигурации. Кроме того, мы представили метод внедрения списка, который может быть полезен в некоторых случаях использования.

Спасибо за чтение. Пожалуйста, поделитесь этой статьей, если она окажется полезной. Еще раз спасибо.