- PVSM.RU - https://www.pvsm.ru -
Доброго времени суток.
Сегодня я решил представить вам перевод цикла статей [1] для подготовки к Spring Professional Certification [2].
Это перевод только первой статьи, если он зайдет аудитории, я продолжу выпуск переводов.

И так, начнем.
Внедрение зависимостей — это специальный паттерн, который уменьшает связь между Spring компонентами. Таким образом, при применении DI, ваш код становится чище, проще, его становится легче понять и тестировать.
Согласно паттерну DI, создание объектов для зависимостей переходит на фабрику или отдается третьей стороне. Это означает, что мы можем сосредоточиться на использовании этих объектов вместо их создания.
В Spring Framework интерфейс org.springframework.factory.BeanFactory предоставляет фабрику для бинов, которая в то же время является IoC контейнером приложения. Управление бинами основано на конфигурации(java или xml).
Интерфейс org.springframework.context.ApplicationContext — это обертка над bean factory, предоставляющая некоторые дополнительные возможности, например AOP, транзакции, безопасность, i18n, и т.п.
Основа Spring Framework — контейнер, и наши объекты "живут" в этом контейнере.
Контейнер обычно создает множество объектов на основе их конфигураций и управляет их жизненным циклом от создания объекта до уничтожения.
Контейнер — это объект, реализующий интерфейс ApplicationContext.
Spring обеспечивает несколько разновидностей контекста.
Есть несколько основных реализаций интерфейса ApplicationContext:
Примеры создания контекста:
ApplicationContext ctx = new FileSystemXmlApplicationContext(
"c:/bean_properties.xml");
ApplicationContext ctx = new AnnotationConfigApplicationContext(
"com.springdemoapp.JavaConfig.class");
BeanFactoryPostProcessorssetBeanName() из интерфейса NameBeanAware, то ID бина передается в методsetBeanFactory() из этого интерфейса.setApplicationContext().BeanPostProcessor это специальный интерфейс(о нем ниже), и Spring позволяет бинам имплементировать этот интерфейс. Реализуя метод postProcessBeforeInitialization(), можно изменить экземпляр бина перед его(бина) инициализацией(установка свойств и т.п.)@PostConstruct или метод initMethod из аннотации @Bean.ApplicationContext#getBean().close() из ApplicationContext), бин уничтожается.@PreDestroy, то перед уничтожением вызовется этот метод. Если бин имплементирует DisposibleBean, то Spring вызовет метод destroy(), чтобы очистить ресурсы или убить процессы в приложении. Если в аннотации @Bean определен метод destroyMethod, то вызовется и он.
Если вы используете JUnit 5, то вам нужно указать 2 аннотации:
Можно использовать аннотацию @SpringJUnitConfig [5], которая сочетает обе эти аннотации.
Для теста веб-слоя можно использовать аннотацию @SpringJUnitWebConfig [6].
Если это не веб-приложение, то есть 2 способа:
registerShutdownHook(), он также реализован в классе AbstractApplicationContext. Это предпочтительный способ.close() из класса AbstractApplicationContext.В Spring Boot приложении:
Чтобы создать класс с конфигурацией на основе Java-кода, нужно аннотировать его с помощью
@Configuration.
Этот класс будет содержать фабричные методы для создания бинов в контейнере.
Эти методы должны быть аннотированы аннотацией @Bean.
Пример:
@Configuration
public class DSConfig {
@Bean
public DataSource dataSource() {
return DataSourceBuilder
.create()
.username("")
.password("")
.url("")
.driverClassName("")
.build();
}
}
Этот класс поместит в контейнер экземпляр класса DataSource. Позднее его можно будет использовать при доступе к базе данных.
Component scanning(сканирование компонентов) — Spring автоматически обнаруживает бины, которые будут находиться в контейнере. Это бины с аннотациями-стереотипами.
Однако сканирование компонентов не включено по умолчанию.
Чтобы включить сканирование, аннотируйте @Configuration-класс аннотацией @ComponentScanning. Spring будет автоматически сканировать тот пакет, в котором находится этот класс и все его подпакеты.
Можно указать и другие пакеты для сканирования, и даже классы:
//сканирует 2 пакета
@Configuration(<i>basePackages</i> = {"soundsystem", "video"})
//сканирует класс
@Configuration(<i>basePackageClasses</i> = "MyClass.class")
Autowiring(внедрение) — Spring автоматически внедрит зависимости во время сканирования или помещения бина в контейнер.
Для внедрения зависимостей используется аннотация @Autowire.
Стереотипы — это аннотации, обозначающие специальную функциональность.
Все стереотипы включают в себя аннотацию @Component.
| Component [7] | Корневая аннотация, которая помечает класс как кандидат для автовнедрения |
| Controller [8] | Указывает, что класс является контроллером для отправления данных на фронт. |
| @RestController | Указывает, что класс является контроллером для REST. Содержит аннотации Controller [8] и @ResponseBody |
| Service [9] | Указывает, что класс является сервисом для выполнения бизнес-логики |
| Repository [10] | Указывает, что класс является репозиторием для работы с бд |
| @Configuration | Указывает, что класс содержит Java-конфигурацию(@Bean-методы) |
Область видимости — scope, скоуп. Существует 2 области видимости по умолчанию.
| Singleton | Область видимости по умолчанию. В контейнере находится всего 1 экземпляр бина |
| Prototype | В контейнере может находится любое количество экземпляров бина |
И 4 области видимости в веб-приложении.
| Request | Область видимости — 1 HTTP запрос. На каждый запрос создается новый бин |
| Session | Область видимости — 1 сессия. На каждую сессию создается новый бин |
| Application | Область видимости — жизненный цикл ServletContext |
| WebSocket | Область видимости — жизненный цикл WebSocket |
Singleton-бины обычно создаются сразу при сканировании.
Prototype-бины обычно создаются только после запроса.
Чтобы указать способ инициализации, можно использовать аннотацию @Lazy.
Она ставится на @Bean-методы, на @Configuration-классы, или на @Component-классы.
В зависимости от параметра(true или false), который принимает аннотация, инициализация будет или ленивая, или произойдет сразу. По умолчанию(т.е. без указания параметра) используется true.
BeanFactoryPostProcessor работает над описаниями бинов или конфигурационными метаданными перед тем, как бин будет создан.BeanFactoryPostProcessor, например, читающий property-файлы и получающий из них свойства бинов.Для того чтобы использовать кастомный BFPP. Вы можете переопределить механизм получения данных из метафайлов.
@Bean
public static PropertySourcesPlaceholderConfigurer pspc() {
//создать, сконфигурировать и вернуть pspc
}
destroyMethod — указывает на метод обратного вызова. Метод находится в бине.initMethod — указывает на метод обратного вызова. Метод находится в бине.name — имя бина. По умолчанию именем бина является имя метода.value — алиас для name()Spring использует несколько BeanPostProcessor’ов.
Например, CommonAnnotationPostProcessor [11] или AutowiredAnnotationBeanPostProcessor [12].
BPP работает с экземплярами бинов, т.е. контейнер создает бин, а затем начинает работать BPP.

Есть 3 варианта для создания таких методов:
@PreDestroy и @PostConstruct аннотации [13]initMethod и destroyMethod в аннотации @Bean, указывающие на методы в классе бинаInitializingBean#afterPropertiesSet() и DisposableBean#destroy(). Для переопределения этих методов нужно имплементировать соответствующие интерфейсы.

Ниже перечислены типы DI, которые могут быть использованы в вашем приложении:
DI через конструктор считается самым лучшим способом, т.к. для него не надо использовать рефлексию, а также он не имеет недостатков DI через сеттер.
DI через поле не рекомендуется использовать, т.к. для этого применяется рефлексия, снижающая производительность.
DI через конструктор может приводить к циклическим зависимостям [15]. Чтобы этого избежать, можно использовать ленивую инициализацию бинов или DI через сеттер.
@Primary, то внедряется он@Autowire + Qualifier, то контейнер будет использовать информацию из @Qualifier, чтобы понять, какой компонент внедрятьКонтейнер обрабатывает DI с помощью AutowiredAnnotationBeanPostProcessor [12]. В связи с этим, аннотация не может быть использована ни в одном BeanFactoryPP или BeanPP.
Если внедряемый объект массив, коллекция, или map с дженериком, то Spring внедрит все бины подходящие по типу в этот массив(или другую структуру данных). В случае с map ключом будет имя бина.
//параметр указывает, требуется ли DI
@Authowired(required = true/false)
Вы можете использовать разные типы внедрения:
Spring предоставляет аннотацию Qualifier [17], чтобы преодолеть проблему неоднозначности при DI.
@Bean
@Qualifier("SomeClass1")
public SomeClass getField() {...}
//…
@Autowire
@Qualifier("SomeField1")
public SomeClass someField;
Если в контейнере есть несколько бинов одного типа(SomeClass), то контейнер внедрит именно тот бин, над @Bean-методом которого стоит соответствующий квалификатор. Также можно не ставить квалификатор на метод, а использовать имя бина в качестве параметра квалификатора.
Имя бина можно можно указать через параметр аннотации Bean [18], а по умолчанию это имя фабричного метода.
Прокси это специальный объект, который имеет такие же публичные методы как и бин, но у которого есть дополнительная функциональность.
Два вида прокси:
Плюсы прокси-объектов:
Если в контейнере нет экземпляра бина, то вызывается @Bean-метод. Если экземпляр бина есть, то возвращается уже созданный бин.
При использовании Java-конфигурации вы можете использовать аннотацию @Profile [19].
Она позволяет использовать разные настройки для Spring в зависимости от указанного профиля.
Ее можно ставить на @Configuration и Component [7] классы, а также на Bean [18] методы.
@Bean("dataSource")
@Profile("production")
public DataSource jndiDataSource() {...}
@Bean("dataSource")
@Profile("development")
public DataSource standaloneDataSource() {...}
Для этого можно использовать аннотацию @Value.
Такие значения можно получать из property файлов, из бинов, и т.п.
@Value("$some.key")
public String stringWithDefaultValue;
В эту переменную будет внедрена строка, например из property или из view.
Как обычно, просьба присылать правки или найденные ошибки в личку.
Автор: Anton
Источник [20]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/java/332301
Ссылки в тексте:
[1] цикла статей: https://github.com/MrR0807/SpringCertification5.0
[2] Spring Professional Certification: https://pivotal.io/training/certification/spring-professional-certification
[3] Study Guide: https://d1fto35gcfffzn.cloudfront.net/academy/Spring-Professional-Certification-Study-Guide.pdf
[4] Внедрение зависимостей, контейнер, IoC, бины: https://habr.com/ru/post/470305/
[5] @SpringJUnitConfig: https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/test/context/junit/jupiter/SpringJUnitConfig.html
[6] @SpringJUnitWebConfig: https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/test/context/junit/jupiter/web/SpringJUnitWebConfig.html
[7] Component: https://habr.com/ru/users/component/
[8] Controller: https://habr.com/ru/users/controller/
[9] Service: https://habr.com/ru/users/service/
[10] Repository: https://habr.com/ru/users/repository/
[11] CommonAnnotationPostProcessor: https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/context/annotation/CommonAnnotationBeanPostProcessor.html
[12] AutowiredAnnotationBeanPostProcessor: https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessor.html
[13] аннотации: https://www.baeldung.com/spring-postconstruct-predestroy
[14] Параметры: https://www.boraji.com/spring-bean-life-cycle-beans-initmethod-and-destroymethod-attributes-example
[15] циклическим зависимостям: https://ru.wikipedia.org/wiki/Dependency_hell
[16] Value: https://habr.com/ru/users/value/
[17] Qualifier: https://habr.com/ru/users/qualifier/
[18] Bean: https://habr.com/ru/users/bean/
[19] @Profile: https://www.baeldung.com/spring-profiles
[20] Источник: https://habr.com/ru/post/470305/?utm_source=habrahabr&utm_medium=rss&utm_campaign=470305
Нажмите здесь для печати.