Главная страница

Ызкштп. Оглавление Введение 61. Что такое инверсия контроля (IoC) и внедрение зависимостей (DI) Как они реализованы в


Скачать 1.17 Mb.
НазваниеОглавление Введение 61. Что такое инверсия контроля (IoC) и внедрение зависимостей (DI) Как они реализованы в
АнкорЫзкштп
Дата01.11.2021
Размер1.17 Mb.
Формат файлаpdf
Имя файлаmetodichka_06_Spring (3).pdf
ТипДокументы
#260853
страница1 из 5
  1   2   3   4   5

Spring
Автор:
Эльдар Суйналиев
При участии:
Антон Таврель
Роман Евсеев

2020 год

Оглавление
Введение
6
1. Что такое инверсия контроля (IoC) и внедрение зависимостей (DI)? Как они реализованы в
Spring?
7
Inversion of Control (IoC)
7
Dependency Injection (DI)
7
2. Что такое IoC Container?
9
3. Что такое Bean в Spring?
10
4. Расскажите про аннотацию @Bean
11
5. Расскажите про аннотацию @Component
13
6. Чем отличаются аннотации @Bean и @Component?
14
7. Расскажите про аннотации @Service и @Repository. В чем различия?
15
8. Расскажите про аннотацию @Autowired
16
9. Расскажите про аннотацию @Resource
18
10. Расскажите про аннотацию @Inject
19
11. Расскажите про аннотацию @Lookup
20
12. Можно ли вставить бин в статическое поле? Почему?
22
13. Расскажите про аннотации @Primary и @Qualifier
23
14. Как заинжектить примитив?
24
@Value
24
@Value with SpEL
24
@Value with Map
25
@Value with Constructor
25
@Value with Setter
26
15. Как заинжектить коллекцию?
27
Array Injection
27
Collections Injection
27
Коллекции бинов одного типа
28
Использование @Qualifier
28
Упорядочивание элементов массивов / списков
29
16. Расскажите про аннотацию @Conditional
32
17. Расскажите про аннотацию @ComponentScan
34
18. Расскажите про аннотацию @Profile
35

19. Расскажите про ApplicationContext и BeanFactory, чем отличаются? В каких случаях что
стоит использовать?
36
BeanFactory
36
ApplicationContext
36
ApplicationContext vs. BeanFactory
36
20. Расскажите про жизненный цикл бина, аннотации @PostConstruct и @PreDestroy()
38
Жизненный цикл бинов
38 1. Парсирование конфигурации и создание BeanDefinition
38 2. Настройка созданных BeanDefinition
39 3. Создание кастомных FactoryBean (только для XML-конфигурации)
39 4. Создание экземпляров бинов
39 5. Настройка созданных бинов
39 6. Бины готовы к использованию
41 7. Закрытие контекста
41
@PostConstruct
41
@PreDestroy
41
21. Расскажите про scope бинов. Какой scope используется по умолчанию? Что изменилось в
пятом Spring?
43
Singleton
43
Prototype
43
Request
43
Session
44
Application
44
Websocket
44
Custom thread scope
45
22. Что такое АОП? Как реализовано в спринге?
46
23. Как спринг работает с транзакциями? Расскажите про аннотацию @Transactional
47
24. Расскажите про паттерн MVC, как он реализован в Spring?
51
MVC (Model-View-Controller)
51
Spring Web MVC
51
25. Что такое ViewResolver?
54
26. Расскажите про шаблон проектирования Front Controller, как он реализован в Spring? 55
27. Чем отличаются Model, ModelMap и ModelAndView?
57
Model
57
ModelMap
57
ModelAndView
57
28. Расскажите про аннотации @Controller и @RestController. Чем они отличаются? Как
вернуть ответ со своим статусом (например 213)?
58
@Controller
58
@RestController
58

ResponseEntity
58
29. В чем разница между Filters, Listeners и Interceptors?
60
Filter
60
Interceptor
60
Filter vs. Interceptor
62
Java Listener
63
30. Можно ли передать в GET-запросе один и тот же параметр несколько раз? Как?
65
31. Как работает Spring Security? Как сконфигурировать? Какие интерфейсы используются? 66
32. Что такое Spring Boot? Какие у него преимущества? Как конфигурируется? Подробно
70
33. Расскажите про нововведения Spring 5
73

Введение
В настоящем материале используется официальная документация и руководства Spring
Framework. Практические примеры преимущественно получены с сайтов, пользующихся популярностью и уважением в мировом сообществе разработчиков: Baeldung и другие.
Использованные версии документаций:
Spring Framework Documentation Version 5.2.7.RELEASE Reference Doc.
Spring Framework 5.2.7.RELEASE API
Если Вы заметите неточность или ошибку, либо захотите дополнить ответ - пиши мне, и мы всё обсудим.

1. Что такое инверсия контроля (IoC) и внедрение зависимостей (DI)? Как
они реализованы в Spring?
Источники:
Spring - Introduction to the Spring IoC Container and Beans
Baeldung - Inversion of Control and Dependency Injection
Martin Fowler - Inversion Of Control
Inversion of Control (IoC)
Инверсия (от латинского inversio) - перестановка.
Инверсия контроля (инверсия управления) — это принцип в разработке программного обеспечения, при котором управление объектами или частями программы передается контейнеру или фреймворку. Чаще всего этот принцип используется в контексте объектно- ориентированного программирования.
В отличие от традиционного программирования, в котором наш пользовательский код обращается напрямую к библиотекам, IoC позволяет фреймворку контролировать ход программы и обращаться к нашему коду, когда это необходимо. Для этого, фреймворки используют абстракции со встроенным дополнительным поведением. Если мы хотим добавить наше собственное поведение, нам нужно расширить классы фреймворка или подключить наши собственные классы.
Преимущества этой архитектуры:
❖ отделение выполнения задачи от ее реализации;
❖ легкое переключение между различными реализациями;
❖ большая модульность программы;
❖ более легкое тестирование программы путем изоляции компонента или проверки его зависимостей и обеспечения взаимодействия компонентов через контракты.
Инверсия управления может быть достигнута с помощью различных механизмов, таких как: шаблон проектирования “Стратегия”, шаблон “Локатор служб”, шаблон “Фабрика” и внедрение зависимостей (DI).
Dependency Injection (DI)
Внедрение зависимостей — это шаблон проектирования для реализации IoC, где инвертируемым (переопределяемым) элементом контроля является настройка зависимостей объекта.
Соединение объектов с другими объектами или «внедрение» объектов в другие объекты выполняется контейнером IoC, а не самими объектами.
В Spring Framework инверсия контроля достигается именно внедрением зависимостей.
В Spring Framework инверсия контроля и внедрение зависимостей считаются одним и тем же.
В Spring Framework внедрение зависимостей описывается как процесс, посредством которого объекты определяют свои зависимости (то есть другие объекты, с которыми они работают) только через аргументы конструктора, аргументы фабричного метода
1
или свойства,
1
Шаблон проектирования “Фабричный метод” предлагает создавать объекты не напрямую, используя оператор new, а через вызов особого статического фабричного метода в классе. Объекты всё равно будут создаваться через оператор new, но делать это будет фабричный метод.
Refactoring Guru -
Фабричный метод
которые устанавливаются в экземпляре объекта после того, как он создан или возвращен из метода фабрики. После чего контейнер IoC внедряет эти зависимости в компонент при его создании.
Мы можем создать зависимость объекта следующим традиционным способом, без использования принципа IoC: public class
Store
{ private
Item item; public
Store
()
{ item = new
ItemImpl1();
}
}
В приведенном выше примере мы создаем экземпляр конкретной реализации интерфейса Item (ItemImpl1) внутри самого класса Store.
Используя DI, мы можем переписать пример без указания конкретной реализации Item, не создавая её внутри нашего объекта, а ожидая её получение извне (от внешнего фреймворка
- контейнера IoC): public class
Store
{ private
Item item; public
Store
(Item item)
{ this
.item = item;
}
}
В данном случае инверсия контроля — это переход контроля над зависимостями от объекта Store к контейнеру IoC. Объект Store более не контролирует инстанцирование своего поля (зависимости) item, не создаёт этот объект самостоятельно, а делегирует этот процесс внешним силам - контейнеру IoC, который в нашем примере передаёт в конструктор Store любую из реализаций Item.
Внедрение зависимостей в Spring Framework может быть сделано через конструкторы, сеттеры или поля.
Отдаем создание и управление объектами на аутсорс Spring-у.

2. Что такое IoC Container?
Источники:
Spring - The IoC Container
Baeldung - The Spring IoC Container
IoC Container
В Spring Framework контейнер отвечает за создание, настройку и сборку объектов, известных как бины, а также за управление их жизненным циклом. Он (контейнер) представлен интерфейсом ApplicationContext.
Spring Framework предоставляет несколько реализаций интерфейса ApplicationContext:
❖ ClassPathXmlApplicationContext и FileSystemXmlApplicationContext - для автономных приложений;
❖ WebApplicationContext - для веб-приложений;
❖ AnnotationConfigApplicationContext - для обычной Java-конфигурации, в качестве аргумента которому передается класс, либо список классов с аннотацией
@Configuration, либо с любой другой аннотацией JSR-330, в том числе и @Component.
Контейнер получает инструкции о том, какие объекты создавать, настраивать и собирать, через метаданные конфигурации, которые представлены в виде XML, Java-аннотаций или Java-кода:
❖ XML - Метаданные считываются из файла с расширением *.xml;
❖ Java-аннотации - В Spring 2.5 появилась поддержка метаданных конфигурации на основе аннотаций, которая использует данные байт-кода для подключения компонентов.
Вместо того, чтобы использовать XML-файл для описания связывания компонентов, разработчик перемещает конфигурацию в сам класс компонента, используя аннотации к соответствующему классу, методу или полю. При этом, сам XML-файл с базовыми настройками остаётся. Контейнер считывает аннотации перед считыванием XML, поэтому, если бин конфигурируется и через аннотации и через XML-файл, то настройки
XML переопределят настройки аннотаций.
❖ Java-код - Начиная со Spring 3.0, используя Java-код, а не файлы XML, мы можем определять настройки в специальном классе, помеченном аннотацией @Configuration.
Появились аннотации @Configuration, @Bean, @Import и @DependsOn и т.д.

3. Что такое Bean в Spring?
Источники:
Spring - The IoC Container
В Spring объекты, образующие основу приложения и управляемые контейнером Spring
IoC, называются бинами.
Бин — это объект, который создается, собирается и управляется контейнером Spring IoC.
Иначе говоря, бин — это просто один из множества объектов в вашем приложении. Бины и их зависимости отражаются в метаданных конфигурации, используемых контейнером.

4. Расскажите про аннотацию @Bean
Источники:
Spring - The IoC Container
Spring - How Java-based Configuration Works Internally
Spring API - @Bean
Stackoverflow - @Configuration vs. @Component
LogicBig - Registering beans within @Component classes
@Bean - Это аннотация Spring Framework, она используется над методом для указания того, что данный метод создает, настраивает и инициализирует новый объект, управляемый
Spring IoC контейнером. Такие методы можно использовать как в классах с аннотацией
@Configuration, так и в классах с аннотацией @Component (или её наследниках).
Позволяет дополнительно определить у бина:
❖ name - имя (уникальный идентификатор) бина;
❖ initMethod - имя метода для вызова во время инициализации бина;
❖ destroyMethod - имя метода для вызова во время удаления бина из контекста;
❖ autowireCandidate - является ли этот бин кандидатом на автоматическое внедрение в другой бин.
Классы, аннотированные @Configuration, проксируются через CGLIB. Классы
@Component или обычные классы не проксируются и не перехватывают вызовы методов с аннотациями @Bean, что означает, что вызовы не будут маршрутизироваться через контейнер и каждый раз будет возвращаться новый экземпляр бина.
Также методы бинов, вызывая друг друга в таких классах, не будут создавать бины, а будет просто выполняться код метода, ведь в данном случае они отработают не через прокси.
CGLIB (Code Generation Library) - Это библиотека инструментария байтов, используемая во многих средах Java, таких как Hibernate или Spring. Инструментарий байт-кода позволяет манипулировать или создавать классы после фазы компиляции программы.
Hibernate использует cglib для генерации динамических прокси. Например, он не вернет полный объект, хранящийся в базе данных, но вернет инструментальную версию хранимого класса, которая лениво загружает значения из базы данных по требованию.
Прокси — это шаблон проектирования. Создаем и используем его для добавления и изменения функционала уже существующих классов. В таком случае, прокси-объект применяется вместо исходного. Обычно он использует тот же метод, что и оригинальный, и в
Java прокси-классы расширяют исходные.
Имена бинов
Имя бина, которое в контейнере является одновременно и его уникальным идентификатором, по умолчанию соответствует имени метода, аннотированного @Bean. Но если требуется указать иное имя, то можно использовать атрибут name, который принимает
String. Однако, атрибут name также может принимать массив String, что позволяет использовать несколько имен. Первый элемент массива будет являться именем и уникальным идентификатором бина, а остальные будут его псевдонимами.
@Bean
({
"b1"
,
"b2"
})
// bean available as 'b1' and 'b2', but not 'myBean'
public
MyBean myBean
()
{
// instantiate and configure MyBean obj return obj;
}

5. Расскажите про аннотацию @Component
Источники:
Spring - @Component and Further Stereotype Annotations
Shell26 - Различия @Component, @Service, @Repository, @Controller
Это аннотация Spring Framework, ею мы помечаем класс, если хотим, чтобы из этого класса был создан бин. Именно эту аннотацию ищет Spring Framework, когда сканирует наши классы. Можно указать имя (Id) для создаваемого бина, а можно не указывать, тогда по умолчанию именем будет название класса с маленькой буквы.
Аннотация @Component имеет наследников: @Repository, @Service и @Controller. Все они являются частными случаями использования @Component для слоёв DAO, сервиса и контроллера MVC соответственно. Также эти аннотации могут иметь дополнительный смысл в будущих версиях Spring Framework. В остальных же случаях достаточно использовать аннотацию
@Component.
Итог:
❖ @Component - Spring определяет этот класс как кандидата для создания bean.
❖ @Service - класс содержит бизнес-логику и вызывает методы на уровне хранилища.
Ничем не отличается от классов с @Component.
❖ @Repository - указывает, что класс выполняет роль хранилища (объект доступа к DAO).
Задача @Repository заключается в том, чтобы отлавливать определенные исключения персистентности и пробрасывать их как одно непроверенное исключение Spring
Framework. Для этого Spring оборачивает эти классы в прокси, и в контекст должен быть добавлен класс PersistenceExceptionTranslationPostProcessor.
❖ @Controller - указывает, что класс выполняет роль контроллера MVC. DispatcherServlet просматривает такие классы для поиска @RequestMapping.
@RequestMapping используется для мапинга (связывания) с URL для всего класса или для конкретного метода обработчика.

6. Чем отличаются аннотации @Bean и @Component?
Источники:
Stackoverflow - @Component versus @Bean
Аннотация @Component (как и @Service и @Repository) используется для автоматического обнаружения и автоматической настройки бинов в ходе сканирования путей к классам.
Аннотация @Bean используется для явного объявления бина, а не для того, чтобы Spring делал это автоматически в ходе сканирования путей к классам:
❖ прописываем вручную метод для создания бина;
❖ делает возможным объявление бина независимо от объявления класса, что позволяет использовать классы из сторонних библиотек, у которых мы не можем указать аннотацию @Component;
❖ с аннотацией @Bean можно настроить initMethod, destroyMethod, autowireCandidate, делая создание бина более гибким.

7. Расскажите про аннотации @Service и @Repository. В чем различия?
Источники:
Spring - The IoC Container
Baeldung - @Component vs @Repository and @Service
Baeldung - Spring Bean Annotations
@Service и @Repository являются частными случаями @Component. Технически они одинаковы, но мы используем их для разных целей.
Задача @Repository заключается в том, чтобы отлавливать определенные исключения персистентности и пробрасывать их как одно непроверенное исключение Spring Framework. Для этого в контекст должен быть добавлен класс PersistenceExceptionTranslationPostProcessor.
Мы помечаем бины аннотацией @Service, чтобы указать, что они содержат бизнес- логику. Так что нет никакого другого предназначения, кроме как использовать ее на уровне сервиса.

8. Расскажите про аннотацию @Autowired
Источники:
Spring - Using @Autowired
Spring API - @Autowired
Baeldung - Guide to Spring @Autowired
Baeldung - @Qualifier vs Autowiring by Name
Shell26 - @Autowired vs @Resource vs @Inject
Это аннотация Spring Framework, ею помечают конструктор, поле, сеттер-метод или метод конфигурации, сигнализируя, что им обязательно требуется внедрение зависимостей.
Если в контейнере не будет обнаружен необходимый для вставки бин, то будет выброшено исключение, либо можно указать @Autowired(required = false), означающее, что внедрение зависимости в данном месте не обязательно.
Аннотация @Autowired является альтернативой Java-аннотации @Inject, не имеющей required = false (зависимость должна быть обязательно внедрена).
Начиная со Spring Framework 4.3, аннотация @Autowired для конструктора больше не требуется, если целевой компонент определяет только один конструктор. Однако, если доступно несколько конструкторов и нет основного/стандартного конструктора, по крайней мере один из конструкторов должен быть аннотирован @Autowired, чтобы указать контейнеру, какой из них использовать.
По умолчанию Spring распознает объекты для вставки по типу. Если в контейнере доступно более одного бина одного и того же типа, будет исключение. Для избежания этого можно указать аннотацию Spring Framework - @Qualifier("fooFormatter"), где fooFormatter — это имя (Id) одного из нескольких бинов одного типа, находящихся в контейнере и доступных для внедрения: public class
FooService
{
@Autowired
@Qualifier
(
"fooFormatter"
) private
Formatter formatter;
}
При выборе между несколькими бинами при автоматическом внедрении используется
имя поля. Это поведение по умолчанию, если нет других настроек. Давайте посмотрим код, основанный на нашем первоначальном примере:
@Component
@Qualifier
(
"fooFormatter"
) public class
FooFormatter implements
Formatter
{
//...
}
@Component
@Qualifier
(
"barFormatter"
) public class
BarFormatter implements
Formatter
{
//...
}
public class
FooService
{
@Autowired private
Formatter fooFormatter;
}
В этом случае Spring определит, что нужно внедрить бин с именем FooFormatter, поскольку имя поля соответствует значению, которое мы использовали в аннотации
@Component для этого бина.
Мы также можем указать Spring предоставить все бины определенного типа из
ApplicationContext, добавив аннотацию @Autowired в поле или метод с массивом или коллекцией этого типа, как показано в следующем примере:
@Autowired private
MovieCatalog[] movieCatalogs;
или:
@Autowired private
Set movieCatalogs;
или:
@Autowired public void setMovieCatalogs
(Set movieCatalogs)
{ this
.movieCatalogs = movieCatalogs;
}
Даже коллекции типа Map могут быть подключены автоматически, если тип ключа -
String. Ключами будут имена бинов, а значениями - сами бины, как показано в следующем примере: public class
MovieRecommender
{ private
MapMovieCatalog> movieCatalogs;
@Autowired public void setMovieCatalogs
(MapMovieCatalog> movieCatalogs)
{ this
.movieCatalogs
= movieCatalogs;
}
//
}

9. Расскажите про аннотацию @Resource
Источники:
Javadoc - @Resource
Baeldung - The @Resource Annotation
Stackoverflow - @Resource vs @Autowired
Shell26 - @Autowired vs @Resource vs @Inject
Java-аннотация @Resource может применяться к классам, полям и методам. Она пытается получить зависимость: сначала по имени, затем по типу, затем по описанию (Qualifier).
Имя извлекается из имени аннотируемого сеттера или поля, либо берется из параметра name.
При аннотировании классов имя не извлекается из имени класса по умолчанию, поэтому оно должно быть указано явно.
Указав данную аннотацию у полей или методов с аргументом name, в контейнере будет произведен поиск компонентов с данным именем, и в контейнере должен быть бин с таким именем:
@Resource
(name=
"namedFile"
) private
File defaultFile;
Если указать её без аргументов, то Spring Framework поможет найти бин по типу.
Если в контейнере несколько бинов-кандидатов на внедрение, то нужно использовать аннотацию @Qualifier:
@Resource
@Qualifier
(
"defaultFile"
) private
File dependency1;
@Resource
@Qualifier
(
"namedFile"
) private
File dependency2;
Разница с @Autowired:
❖ ищет бин сначала по имени, а потом по типу;
❖ не нужна дополнительная аннотация для указания имени конкретного бина;
❖ @Autowired позволяет отметить место вставки бина как необязательное
@Autowired(required = false);
❖ при замене Spring Framework на другой фреймворк, менять аннотацию @Resource не нужно.

10. Расскажите про аннотацию @Inject
Источники:
Javadoc - @Inject
Baeldung - The @Resource Annotation
Shell26 - @Autowired vs @Resource vs @Inject
Java-аннотация @Inject входит в пакет javax.inject и, чтобы её использовать, нужно добавить зависимость:


javax.inject


javax.inject


1


Размещается над полями, методами, и конструкторами с аргументами. @Inject как и
@Autowired в первую очередь пытается подключить зависимость по типу, затем по описанию и только потом по имени. Это означает, что даже если имя переменной ссылки на класс отличается от имени компонента, но они одинакового типа, зависимость все равно будет разрешена:
@Inject private
ArbitraryDependency fieldInjectDependency;
отличается от имени компонента, настроенного в контексте приложения:
@Bean public
ArbitraryDependency injectDependency
()
{
ArbitraryDependency injectDependency = new
ArbitraryDependency(); return injectDependency;
}
Разность имён injectDependency и fieldInjectDependency не имеет значения, зависимость будет подобрана по типу ArbitraryDependency.
Если в контейнере несколько бинов-кандидатов на внедрение, то нужно использовать аннотацию @Qualifier:
@Inject
@Qualifier
(
"defaultFile"
) private
ArbitraryDependency defaultDependency;
@Inject
@Qualifier
(
"namedFile"
) private
ArbitraryDependency namedDependency;
При использовании конкретного имени (Id) бина используем @Named:
@Inject
@Named
(
"yetAnotherFieldInjectDependency"
) private
ArbitraryDependency yetAnotherFieldInjectDependency;

11. Расскажите про аннотацию @Lookup
Источники:
Sysout - Как использовать аннотацию @Lookup
Обычно бины в приложении Spring являтся синглтонами, и для внедрения зависимостей мы используем конструктор или сеттер.
Но бывает и другая ситуация: имеется бин Car – синглтон (singleton bean), и ему требуется каждый раз новый экземпляр бина Passenger. То есть Car – синглтон, а Passenger – так называемый прототипный бин (prototype bean). Жизненные циклы бинов разные. Бин Car создается контейнером только раз, а бин Passenger создается каждый раз новый – допустим, это происходит каждый раз при вызове какого-то метода бина Car. Вот здесь-то и пригодится внедрение бина с помощью Lookup-метода. Оно происходит не при инициализации контейнера, а позднее: каждый раз, когда вызывается метод.
Суть в том, что мы создаём метод-заглушку в бине Car и помечаем его специальным образом – аннотацией @Lookup. Этот метод должен возвращать бин Passenger, каждый раз новый. Контейнер Spring под капотом создаст прокси-подкласс и переопределит этот метод и будет нам выдавать новый экземпляр бина Passenger при каждом вызове аннотированного метода. Даже если в нашей заглушке он возвращает null (а так и надо делать - всё равно этот метод будет переопределен в прокси-подклассе):
@Component public class
Car
{
@Lookup public
Passenger createPassenger
()
{ return null
;
} public
String drive
(String name)
{
Passenger passenger = createPassenger(); passenger.setName(name); return
"car with "
+ passenger.getName();
}
}
Допустим, в бине есть метод drive(), и при каждом вызове метода drive() бину Car требуется новый экземпляр бина Passenger – сегодня пассажир Петя, завтра – Вася. То есть бин
Passenger прототипный. Для получения этого бина надо написать метод-заглушку createPassenger() и аннотировать его с помощью @Lookup.
Контейнер Spring переопределит этот метод-заглушку и будет выдавать при его вызове каждый раз новый экземпляр Passenger.
Осталось только определить бин Passenger как прототипный:
@Component
@Scope
(
"prototype"
) public class
Passenger
{ private
String name; public
String getName
()
{ return name;
} public void setName
(String name)
{
this
.name = name;
}
}
Теперь при вызове метода drive() мы можем везти каждый раз нового пассажира. Имя его передаётся в аргументе метода drive(), и затем задается сеттером во вновь созданном экземпляре пассажира.

12. Можно ли вставить бин в статическое поле? Почему?
Источники:
Mkyong - Inject value into static variables
Stackoverflow - Can you use @Autowired with static fields?
Stackoverflow - Why can't we autowire static fields in spring?
Spring не позволяет внедрять бины напрямую в статические поля, например:
@Component public class
TestDataInit
{
@Autowired private static
OrderItemService orderItemService;
}
Если вы распечатаете TestDataInit.orderItemService, там будет null.
Чтобы исправить это, создайте нестатический сеттер-метод:
@Component public class
TestDataInit
{ private static
OrderItemService orderItemService;
@Autowired public void setOrderItemService
(OrderItemService orderItemService)
{
TestDataInit.orderItemService = orderItemService;
}
}

13. Расскажите про аннотации @Primary и @Qualifier
Источники:
Baeldung - Spring @Primary Annotation
Baeldung - Spring @Qualifier Annotation
Мы используем @Primary, чтобы отдавать предпочтение бину, когда есть несколько бинов одного типа. Эта аннотация полезна, когда мы хотим указать, какой компонент определенного типа должен внедряться по умолчанию.
@Configuration public class
Config
{
@Bean public
Employee
JohnEmployee
()
{ return new
Employee(
"John"
);
}
@Bean
@Primary public
Employee
TonyEmployee
()
{ return new
Employee(
"Tony"
);
}
}
или с аннотацией @Component
@Component public class
DepartmentManager implements
Manager
{
@Override public
String getManagerName
()
{ return
"Department manager"
;
}
}
@Component
@Primary public class
GeneralManager implements
Manager
{
@Override public
String getManagerName
()
{ return
"General manager"
;
}
}
Теперь, где будут требоваться бины типа Employee и Manager будут созданы и внедрены
TonyEmployee и GeneralManager.
Когда есть несколько бинов одного типа, подходящих для внедрения, аннотация
@Qualifier позволяет указать в качестве аргумента имя конкретного бина, который следует внедрить.
Стоит отметить, что если присутствуют аннотации @Qualifier и @Primary, то аннотация
@Qualifier будет иметь приоритет. По сути, @Primary определяет значение по умолчанию, в то время как @Qualifier более специфичен.

14. Как заинжектить примитив?
Источники:
Baeldung - Spring @Value Annotation
@Value
Внедрить в поле примитив можно с помощью аннотации @Value на уровне параметров поля или конструктора/метода.
Нам понадобится файл свойств (*.properties), чтобы определить значения, которые мы хотим внедрить аннотацией @Value. Сначала в нашем классе конфигурации нам нужно указать аннотацию @PropertySource с именем файла свойств.
@Component
@PropertySource
(
"classpath:values.properties"
) public class
CollectionProvider
{
}
Содержимое файла values.properties: value.from.file=Value got from the file priority=high listOfValues=A,B,C
Внедряем значение value.from.file, равное “Value got from the file”:
@Value
(
"${value.from.file}"
) private
String valueFromFile;
Если из файла не подтянутся значения по тем или иным причинам, то можно указать значения, которые будут внедрены по умолчанию. В данном примере, если не будет доступен value.from.file, то внедрится значение “some default”:
@Value
(
"${value.from.file:some default}"
) private
String someDefault;
Если нужно внедрить несколько значений, то можно их определить в файле *.properties через запятую и Spring внедрит их как массив:
@Value
(
"${listOfValues}"
) private
String[] valuesArray;
@Value with SpEL
Кроме того, для внедрения значений мы можем использовать язык SpEL (Spring
Expression Language):
@Value
(
"#{systemProperties['priority']}"
) private
String spelValue;
или со значениями по умолчанию:
@Value
(
"#{systemProperties['unknown'] ?: 'some default'}"
) private
String spelSomeDefault;
Мы можем использовать значение поля из другого бина. Предположим, у нас есть бин с именем someBean с полем someValue, равным 10. Тогда в этом примере в поле будет записано число 10:

@Value
(
"#{someBean.someValue}"
) private
Integer someBeanValue;
Мы можем манипулировать свойствами, чтобы получить список значений. В следующем примере мы получаем список строковых значений A, B и C:
@Value
(
"#{'${listOfValues}'.split(',')}"
) private
List valuesList;
@Value with Map
Мы также можем использовать аннотацию @Value для добавления свойств в Map. Для начала нам нужно определить свойство в формате {key: ‘value '} в нашем файле свойств: valuesMap={key1:
'1'
, key2:
'2'
, key3:
'3'
}
Теперь мы можем вставить это значение из файла свойств в виде карты:
@Value
(
"#{${valuesMap}}"
) private
Map valuesMap;
Можем просто внедрить значение по ключу:
@Value
(
"#{${valuesMap}.key1}"
) private
Integer valuesMapKey1;
Если мы не уверены, содержит ли Map определенный ключ, мы должны выбрать более безопасное выражение, которое не будет генерировать исключение, а установит значение в null, если ключ не найден:
@Value
(
"#{${valuesMap}['unknownKey']}"
) private
Integer unknownMapKey;
Мы также можем установить значения по умолчанию для свойств или ключей, которые могут не существовать:
@Value
(
"#{${unknownMap : {key1: '1', key2: '2'}}}"
) private
Map unknownMap;
@Value
(
"#{${valuesMap}['unknownKey'] ?: 5}"
) private
Integer unknownMapKeyWithDefaultValue;
Записи карты также могут быть отфильтрованы перед внедрением. Предположим, нам нужно получить только те записи, значения которых больше единицы:
@Value
(
"#{${valuesMap}.?[value>'1']}"
) private
Map valuesMapFiltered;
Мы также можем использовать аннотацию @Value для добавления всех текущих системных свойств:
@Value
(
"#{systemProperties}"
) private
Map systemPropertiesMap;
@Value with Constructor
Мы можем внедрять значения в конструкторе, если оно не найдено, то будет внедрено значение по умолчанию:
@Component
@PropertySource
(
"classpath:values.properties"
) public class
PriorityProvider
{
private
String priority;
@Autowired public
PriorityProvider
(@Value(
"${priority:normal}"
)
String priority) { this
.priority = priority;
}
// standard getter
}
@Value with Setter
В приведенном коде мы используем выражение SpEL для добавления списка значений в метод setValues:
@Component
@PropertySource
(
"classpath:values.properties"
) public class
CollectionProvider
{ private
List values = new
ArrayList<>();
@Autowired public void setValues
(
@Value(
"#{'${listOfValues}'.split(',')}"
)
List values) { this
.values.addAll(values);
}
// standard getter
}

15. Как заинжектить коллекцию?
Источники:
LogicBig - Spring - Injecting Arrays and Collections
Habr - Некоторые тонкости injection'а коллекций в Spring'е
Array Injection
Мы можем вставлять массивы примитивов и ссылочных типов. Со всеми массивами и коллекциями мы можем использовать внедрение через конструкторы, сеттеры или поля.
@Configuration public class
ArrayExample
{
@Bean public
TestBean testBean
()
{ return new
TestBean();
}
@Bean public
String[] strArray(){ return new
String[]{
"two"
,
"three"
,
"four"
};
} public class
TestBean
{ private
String[] stringArray;
@Autowired public void setStringArray
(String[] stringArray)
{ this
.stringArray = stringArray;
}
}
Collections Injection
public class
ListExample
{
@Bean public
TestBean testBean
()
{ return new
TestBean();
}
@Bean public
List strList
()
{ return
Arrays.asList(
"two"
,
"three"
,
"four"
);
}
} public class
TestBean
{ private
List stringList;
@Autowired public void setStringList
(List stringList)
{ this
.stringList = stringList;
}
}

Коллекции бинов одного типа
Также мы можем собрать все бины одного типа, находящиеся в контейнере, и внедрить их в коллекцию или массив:
@Configuration public class
SetInjection
{
@Bean public
TestBean testBean
()
{ return new
TestBean();
}
@Bean public
RefBean refBean1
()
{ return new
RefBean(
"bean 1"
);
}
@Bean public
RefBean refBean2
()
{ return new
RefBean2(
"bean 2"
);
}
@Bean public
RefBean refBean3
()
{ return new
RefBean3(
"bean 3"
);
} public static class
TestBean
{
// All bean instances of type RefBean will be injecting here
@Autowired private
Set refBeans;
} public static class
RefBean
{ private
String str; public
RefBean
(String str)
{ this
.str = str;
}
}
}
Если мы хотим внедрить вышеупомянутые бины RefBean в Map, то значениями Map будут сами бины, а ключами будут имена бинов:
{refBean1 = RefBean{str=
'bean 1'
}, refBean2 = RefBean{str=
'bean 2'
}, refBean3 =
RefBean{str=
'bean 3'
}}
Использование @Qualifier
Методы класса JavaConfig (те, которые аннотированы @Bean) могут быть объявлены с определенным квалифицирующим типом, используя @Qualifier. Мы использовали параметр 'name' у аннотации @Bean, чтобы указать конкретный классификатор для бина. Но элемент 'name', на самом деле, является не столько именем, сколько идентификатором бина, который должен быть уникальным, потому что все бины хранятся в контейнере в Map.
В случае с коллекцией мы хотим, чтобы несколько бинов имели одно и то же имя квалификатора, чтобы их можно было внедрить в одну коллекцию с одним и тем же
квалификатором. В этом случае мы должны использовать аннотацию @Qualifier вместе с @Bean вместо элемента name.
@Configuration public class
SetInjection
{
@Bean public
TestBean testBean
()
{ return new
TestBean();
}
@Bean public
RefBean refBean1
()
{ return new
RefBean(
"bean 1"
);
}
@Bean
@Qualifier
(
"myRefBean"
) public
RefBean refBean2
()
{ return new
RefBean2(
"bean 2"
);
}
@Bean
@Qualifier
(
"myRefBean"
) public
RefBean refBean3
()
{ return new
RefBean3(
"bean 3"
);
} public static class
TestBean
{
@Autowired
@Qualifier
(
"myRefBean"
) private
Set refBeans;
}
}
Только бины с именами refBean2 и refBean3 попадут в коллекцию, так как у них одинаковые квалификаторы - myRefBean.
Упорядочивание элементов массивов / списков
Бины могут быть упорядочены, когда они вставляются в списки (не Set или Map) или массивы. Поддерживаются как аннотация @Order, так и интерфейс Ordered. Например:
@Configuration public class
ArrayExample
{
@Bean public
TestBean testBean
()
{ return new
TestBean();
}
@Bean
@Order
(
3
) public
String refString1
()
{ return
"my string 1"
;
}
@Bean
@Order
(
1
) public
String refString2
()
{ return
"my string 2"
;
}

@Bean
@Order
(
2
) public
String refString3
()
{ return
"my string 3"
;
} private static class
TestBean
{ private
String[] stringArray;
@Autowired public void setStringArray
(String[] stringArray)
{ this
.stringArray = stringArray;
} public
String[] getStringArray () { return stringArray;
}
}
}
Массив строк будет выглядеть так:
[my string
2
, my string
3
, my string
1
]
Также мы можем объявить бин-коллекцию и внедрять её в другие бины:
@Service
@Getter public class
ActionHeroesService
{
@Autowired
List
  1   2   3   4   5


написать администратору сайта