Spring Framework основан на двух принципах: “Dependency Injection” и “Aspect Oriented Programming“

Цель этой статьи показать пример работы dependency injection в фреймворке Spring. Конфигурирование фреймворка Spring можно осуществлять с помощью XML файлов или используя аннотации. В этой статье приведен пример использования обоих подходов. Также приведен пример JUnit тестов, для того чтобы показать простоту тестирования приложений использующих dependency injection.
Создан maven проект spring-dependency-injection, его структура выглядит следующим образом:

project

Теперь рассмотрим в деталях каждый его элемент.

 

Spring Maven Dependencies

Добавлены зависимости фреймворка Spring и библиотеки JUnit в файл pom.xml

Файл pom.xml выглядит следующим образом:pom.xml

На данный момент стабильной версией Spring Framework является  4.2.4.RELEASE и JUnit версия 4.12, если вы используете другие версии, значит есть вероятность что нужно будет внести некоторые изменения в проект. Когда вы будете собирать проект вы можете заметить что maven добавит в проект  джарники согласно зависимостям указанным выше в pom.xml файле.

Service Classes

Например нужно отправлять уведомления пользователям используя email и twitter.

Чтобы использовать dependency injection нужно создать базовый класс для этих сервисов. Ниже приведён интерфейс MessageService с методом для отправки сообщений.

MessageService.java

Ниже приведёны классы с имплементацией для отправки email и twitter сообщений.

EmailService.java

TwitterService.java

 

Component Classes

Нужно создать класс который будет использовать сервисы приведенные выше. Создадим две реализации такого класса — первая с использованием Spring аннотаций и вторая без использования аннотаций, которая будет сконфигурированная в XML файле.

MyApplication.java

Разберем некоторые моменты из класса MyApplication:
@Component — аннотация которая ставится перед классом, когда Spring framework будет сканировать проект этот класс будет рассматриваться как компонент.
Аннотация @Component может применяться только к классам и ее retention policy — Runtime.
@Autowired — аннотация которая используется чтобы сказать фреймворку Spring что нужно задействовать автоматическое связывание(autowiring). Аннотация @Autowired может применяться к полю, конструктору и методам класса. Эта аннотация дает нам возможность имплементировать dependency injection в нашем компоненте. Например в этом примере я применил dependency injection используя поле класса(method-based). Вы можете раскомментировать конструктор чтобы использовать его для применения (constructor-based) dependency injection.

Пример класса без аннотаций.

MyXMLApplication.java

Используя XML конфигурацию можно имплементировать dependency injection используя конструктор(constructor-based) или метод(method-based). Нужно отметить что setter-based подход и method-based подход это одно и тоже.

Spring Configuration with Annotations

Для использования конфигурирования с помощью аннотаций нужно создать еще один класс, например DIConfiguration. Он используется для инъекций нужных бинов имплементаций в компонент.

DIConfiguration.java

Разберем некоторые моменты из класса MyApplication:
@Configuration — аннотация которая используется для того чтобы сказать фреймворку Spring данный класс является конфигурационным.
@ComponentScan — аннотация которая используется вместе с аннотацией @Configuration и используем ее для определения пакета в котором нужно искать классы компоненты.
@Bean — аннотация которая используется для того чтобы сказать фреймворку Spring что данный метод нужно использовать как бин для инъекций в классы компоненты.

Ниже приведена программа которая будет тестировать пример сконфигурированный с помощью аннотаций.

ClientApplication.java

Разберем некоторые моменты из класса ClientApplication. AnnotationConfigApplicationContext это имплементация абстрактного класса AbstractApplicationContext, его используют для автоматического связывания(autowiring) сервисов с компонентами когда используют аннотации для конфигурации фреймворка Spring.
Конструктор класса AnnotationConfigApplicationContext принимает параметром класс который будет использовать для получения бина имплементации и дальнейшей вставки его в компонент.
Метод getBean(Class) возвращает объект компонента и использует конфигурацию для автоматического связывания(autowiring) объектов.
Поскольку объекты контекста является ресурсоемкими нам нужно закрывать эти ресурсы после завершения работы с ними.

Результат после запуска этой программы:


фев 05, 2016 12:07:11 AM org.springframework.context.annotation.AnnotationConfigApplicationContext prepareRefresh
INFO: Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@5d099f62: startup date [Fri Feb 05 00:07:11 EET 2016]; root of context hierarchy
Email Sent to dmytro@becomejavasenior.com with Message=Hi Dmytro
фев 05, 2016 12:07:12 AM org.springframework.context.annotation.AnnotationConfigApplicationContext doClose
INFO: Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@5d099f62: startup date [Fri Feb 05 00:07:11 EET 2016]; root of context hierarchy

Spring XML Based Configuration

XML файл для конфигурирования фреймворка Spring. Название файла не имеет особого значения.

applicationContext.xml

applicationContext.xml

 

Нужно отметить что в приведенном выше XML файле есть пример конфигурирования обоих подходов применения dependency injection: constructor-based и setter-based.
Поскольку в MyXMLApplication.java используется сеттер для инъекции — конфигурация этого бина содержит property элемент для инъекции. Для constructor-based инекции нужно использовать constructor-arg тег.

Файл с XML конфигурацией должен размещаться в папке с ресурсами.

Программа которая будет тестировать пример сконфигурированный с помощью XML.

ClientXMLApplication.java

Разберем некоторые моменты из класса ClientXMLApplication.
ClassPathXmlApplicationContext используется для получения объекта ApplicationContext используя файл конфигурации. Также можно передать несколько конфигурационных файлов.

Результат после запуска этой программы:

фев 05, 2016 12:21:13 AM org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh
INFO: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@7daf6ecc: startup date [Fri Feb 05 00:21:12 EET 2016]; root of context hierarchy
фев 05, 2016 12:21:13 AM org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
INFO: Loading XML bean definitions from class path resource [applicationContext.xml] Twitter message Sent to dmytro@becomejavasenior.com with Message=Hi Dmytro
фев 05, 2016 12:21:13 AM org.springframework.context.support.ClassPathXmlApplicationContext doClose
INFO: Closing org.springframework.context.support.ClassPathXmlApplicationContext@7daf6ecc: startup date [Fri Feb 05 00:21:12 EET 2016]; root of context hierarchy

Spring JUnit Test Case

Одним из преимуществ dependency injection является простота в создании mock классов сервисов в отличии от использования сервисов без DI.

Пример теста с использованием JUnit 4.

[/fusion_builder_column][/fusion_builder_row][/fusion_builder_container]

Если вы нашли ошибку, пожалуйста, выделите фрагмент текста и нажмите Ctrl+Enter.