Статьи

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

Изучите концепции внедрения зависимостей и инверсии управления, а затем посмотрите, как Spring Framework поддерживает их, с помощью примеров кода.

Инверсия контроля

Прежде чем мы начнем с чего-нибудь, давайте узнаем, что такое инверсия контроля .
Инверсия элемента управления — это термин, используемый в объектно-ориентированном программировании, с помощью которого управление объектом или набором объектов передается платформе или контейнеру, предоставляемому платформой.

Spring Dependency Injection

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

Подробнее о инъекции зависимостей весной:

Spring Inversion of Control похожа. Мы хотим, чтобы наши программные компоненты выполняли свою работу. Мы берем конфигурации и зависимости из компонентов и передаем их в контейнер, называемый Inversion of Control Container или IOC Container. Подробнее в следующих разделах.

Хотите узнать больше о Spring Framework?

Прочитай это:

Что такое зависимость?

Приложение состоит из нескольких классов. Обычно каждый класс должен иметь свою собственную ответственность. Это приводит к тому, что наши классы интегрируются с различными классами для выполнения определенных функций. Когда класс A вызывает метод класса B. Тогда класс A зависит от класса B.

Плотно связанные объекты

Узнайте, как наличие зависимости может привести к проблеме Tightly Coupled Objects . Посмотрите код ниже.

Это FileUploadService который захватывает файл, проверяет, имеет ли файл одно из ожидаемых расширений, и запрашивает FileStorageService для сохранения файла.

01
02
03
04
05
06
07
08
09
10
11
public class FileUploadService {
  
    private List<String> validFiles = Arrays.asList("xls", "doc"."txt", "ppt");
    private FileStorageService service = new AzureBlobStorageService();
  
    public FileUploadService() {}
  
    //
    // Other methods
    //
}

В приведенном выше коде мы используем принцип « Программа-интерфейс» для создания экземпляра FileStorageService . Но, тем не менее, соответствующая реализация жестко запрограммирована в классе. Также validFiles жестко закодирован. Оба они вызывают плотно связанные объекты.

Слабосвязанные объекты

Давайте немного обновим FileUploadService и мы получим объекты со FileUploadService связью .

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
public class FileUploadService {
  
    private List<String> validFiles;
    private FileStorageService service;
     
    public FileUploadService(List<String> validFiles, FileStorageService service){
        this.validFiles = validFiles;
        this.service = service;
    }
}
  
class User {
    public static void main(String[] ar) {
        List<String> validFiles = Arrays.asList("xls", "ppt", "doc");
        FileStorageService service = new AzureBlobStorageService();
         
        FileUploadService fileUploadService = new FileUploadService(validFiles, service);
    }
}
  • Строка № 3: переменная объявлена ​​и не инициализирована. Нет жестко закодированного значения.
  • Строка № 4: только ссылка на тип FileStorageService . Нет реализации прилагается.
  • Строка № 6: Все аргументы конструктора.

Давайте посмотрим, что происходит в классе User , который фактически является пользователем FileUploadService .

  • Строка № 17: Экземпляр FileUploadService создается путем передачи всех необходимых аргументов в конструктор.

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

То, что мы только что сделали, называется инъекцией зависимости .

Внедрение зависимостей — это термин, используемый в объектно-ориентированном программировании , при котором объекты будут сосредоточены на выполнении назначенных функций и использовании других объектов. Необходимые конфигурации и инициализации не будут обрабатываться объектами. Тем не менее, Объекты предоставят способ инициализировать их и их зависимости с помощью назначения поля, установщиков поля или конструкторов. Таким образом, внешние объекты могут инициализировать вещи, а не фактические объекты.

В приложении на основе Spring Inversion of Control Container (контейнер IoC) выполняет внедрение зависимостей. Мы увидим это в следующем разделе. Сначала посмотрим, зачем нам вообще такой контейнер.

Зачем нам нужен контейнер IoC?

Я изменил предыдущий пример кода. Теперь это ResumeUploaderService . Candidate может поделиться своим резюме с ResumeUploaderService . После проверки расширения служба должна предоставить к нему ResumeStorageService к ResumeStorageService . Согласно текущей стратегии организации, резюме хранятся в конфиденциальной папке файловой системы ( FileSystemResumeStorageService ).

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
public class ResumeUploaderService {
  
    private List<String> validFiles;
    private ResumeStorageService service;
  
    public ResumeUploaderService(List<String> validFiles, ResumeStorageService service) {
        this.validFiles = validFiles;
        this.service = service;
    }
}
  
  
class Candidate {
    public static void main(String[] ar) {
        List<String> validFiles = Arrays.asList("pdf", "doc");
  
        String filePath = "/Users/app/confidential/storage/resume";
        ResumeStorageService service = new FileSystemResumeStorageService(filePath);
  
        ResumeUploaderService fileUploadService = new ResumeUploaderService(validFiles, service);
    }
}
  • Строка # 4: ResumeUploaderService имеет ссылку на ResumeStorageService .
  • Строка # 6: Конструктор, который принимает и устанавливает реализацию ResumeStorageService .

Чтобы загрузить резюме, Candidate должен создать экземпляр ResumeUploaderService и передать резюме. Но со всем, что dependency injection , работа кандидата стала трудной. Кандидат должен будет не только создать экземпляр ResumeUploaderService но и ResumeStorageService . Потому что первое не может быть создано без последующего.

  • Строка № 17: Кандидат решает, где хранить резюме (я знаю .. это смешно!)
  • Строка № 18: Кандидат решает, использовать ли FileSystemResumeStorageService или AzureBlobStorageService .
  • Строка № 20. Наконец, кандидат создает экземпляр ResumeUploaderService .

Ниже приведены важные вопросы с выше

  • Потребитель знает слишком много.
  • Потребитель, вместо того, чтобы использовать сервис, также инициализирует его.
  • Потребитель не должен беспокоиться о том, как ResumeUploaderService выполняет свою работу (отсутствие абстракции).
  • Конечный потребитель, мы должны знать все и должны инициализировать все в системе.

Это ясно указывает на то, что нам нужно что-то, что может позаботиться обо всех конфигурациях и инициализации. Нечто, чья единственная ответственность заключается в управлении инициализацией.

Инверсия Контейнера Контроля (Контейнер IoC)

Spring предоставляет IoC-контейнер для решения проблемы. Этот контейнер создает экземпляры всех объектов и одновременно разрешает их зависимости. Класс ApplicationContext представляет контейнер Spring IOC. Контекст приложения отвечает за создание, настройку и подключение компонентов.
Помните, что Beans — это не что иное, как объекты Java, зарегистрированные в контексте приложения Spring.

Для настройки, создания экземпляра или написания bean-компонентов для контекста приложения требуются некоторые инструкции. Эти инструкции могут быть предоставлены в форме конфигураций XML, аннотаций Java или кода.

Spring Dependency Injection

Весной каждый объект — это боб. Каждый объект имеет id или name . ApplicationContext отслеживает все такие события и идентификаторы. Когда потребитель запрашивает компонент, контекст приложения возвращает экземпляр компонента. Посмотрите на приведенный ниже код, чтобы понять детали создания и подключения bean-компонентов.

Spring Dependency Injection
01
02
03
04
05
06
07
08
09
10
11
12
13
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
  
@Component("resumeStorageService")
public class FileSystemResumeStorageService implements ResumeStorageService {
  
    @Value("${resume.storage.path}")
    private String storagePath;             // Storage path assigned based on properties file
  
    //
    // Skipped methods
    //
}
  • Строка # 4: сообщает Spring, чтобы зарегистрировать этот класс как Бин и идентифицировать его по заданному имени. Если имя не указано, имя класса считается идентификатором.
  • Строка № 8. Путь к хранилищу теперь напрямую добавляется из файла свойств. Нет необходимости для потребителя, чтобы передать его.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
  
@Component
public class ResumeUploaderService {
  
    @Autowired
    @Qualifier("resumeStorageService")
    private ResumeStorageService storageService;
  
  
    public ResumeUploaderService(ResumeStorageService storageService) {
        this.storageService = storageService;
    }
  
    //
    // Skipped methods
    //
}
  • Строка # 5: объявляет класс как Spring Bean и имя класса как идентификатор.
  • Строка # 10: сообщает пружине Auto Wire реализацию ResumeStorageService которая определяется как "resumeStorageService" .

Если мы хотим присоединить другую реализацию ResumeStorageService ResumeUploaderService вообще не изменится.

1
2
3
4
5
6
7
8
9
import org.springframework.beans.factory.annotation.Autowired;
  
public class Candidate {
    @Autowired private ResumeUploaderService resumeUploaderService;
  
    public void upload(Byte[] resume) {
        resumeUploaderService.uploadResume(resume);
    }
}
  • Строка № 4: просит Spring назначить экземпляр resumeUploaderService .

Все так чисто и целенаправленно. Ни один класс не инициализирует другой класс или не устанавливает какую-либо конфигурацию для другого класса. Все управляется с помощью Spring Inversion of Control Container (IoC Container) .

Резюме

Вы подошли к концу руководства по внедрению зависимостей и инверсии пружин . Вы узнали, что такое зависимость и как классы могут быть тесно или слабо связаны . Мы поняли концепции внедрения зависимостей и управления в объектно-ориентированном программировании . Вы также узнали, что Spring Inversion of Control Container (IoC Container) управляет всеми инъекциями зависимостей в нашем приложении Spring.

Есть еще много вещей, чтобы узнать о инъекции зависимости Спрингс. Мы рассмотрим их в последующих уроках.

Смотрите оригинальную статью здесь: Spring Inpendency Injection и Inversion of Control

Мнения, высказанные участниками Java Code Geeks, являются их собственными.