# Cобеседование по Java. Разбор вопросов и ответов.       Нажмите ★, если вам нравится проект. Ваш вклад сердечно ♡ приветствуется. Если вам интересно мое резюме: https://github.com/DEBAGanov 1. Что такое Spring Framework? 35. Какие основные преимущества Spring Framework? 36. Что такое IoC (Inversion of Control) и DI (Dependency Injection)? 37. Какие способы реализации DI вы знаете? 38. Какие архитектурные шаблоны используются в Spring Framework? 39. Что такое AOP (Aspect-Oriented Programming)? 40. Какие аннотации в Spring Framework вы знаете? Для чего они используются? 41. Как использовать Spring MVC для создания web-приложений? 42. Какие компоненты Spring MVC вы знаете? 43. Какой контейнер сервлетов поддерживает Spring MVC? 44. Как обрабатывать исключения в Spring MVC? 45. Как обрабатывать формы в Spring MVC? 46. Как производится валидация данных в Spring MVC? 47. Как использовать Hibernate в Spring Framework? 48. Как использовать JDBC Template в Spring Framework? 49. Как использовать JPA в Spring Framework? 50. Какие ORM фреймворки вы знаете? Как они работают с Spring Framework? 51. Какие библиотеки доступны для работы с базами данных в Spring Framework? 52. Как использовать Spring Security для обеспечения безопасности в web-приложениях? 53. Как обеспечить транзакционность в Spring Framework? 54. Какие уровни логирования вы знаете? Как настроить логирование в Spring Framework? 55. Как использовать Spring Boot для создания приложений? 56. Что такое RESTful сервисы? Как их можно реализовать в Spring Framework? 57. Как добавить Swagger в ваше Spring Boot приложение? 58. Как работать с Kafka в Spring Framework? 59. Что такое RabbitMQ? Как его использовать в Spring Framework? 60. Как работать с NoSQL базами данных в Spring Framework? 61. Что такое Spring Cloud? Какие компоненты он включает? 62. Как использовать Spring Data JPA для работы с базами данных? 63. Как использовать Spring Batch для пакетной обработки данных? 64. Как использовать Spring Integration для интеграции приложений? 65. Как использовать Spring Mobile для разработки мобильных приложений? 66. Как использовать Spring Social для интеграции приложений социальных сетей? 67. Как использовать Spring Web Services для разработки веб-сервисов? 68. Как использовать Spring HATEOAS для создания RESTful сервисов с гиперссылками? 69. Как использовать Spring WebSocket для обмена данными в реальном времени? 70. Как использовать Spring AMQP для работы с асинхронной очередью сообщений? 71. Как использовать Spring Cloud Stream для разработки приложений, работающих с потоками данных? 72. Как использовать Spring Cloud Config для централизованного управления конфигурацией приложений? 73. Как использовать Spring Cloud Netflix для разработки микросервисных приложений? 74. Как использовать Spring Cloud Kubernetes для развертывания и управления контейнерами на Kubernetes? 75. Как используются тесты в Spring Framework? 76. Какие типы тестов вы знаете? Какие инструменты для тестирования вам известны? 77. Как тестировать RESTful сервисы в Spring Framework? 78. Как тестировать JPA репозитории в Spring Framework? 79. Как использовать Mockito для создания заглушек? 80. Какие фреймворки и библиотеки используются в экосистеме Spring? 81. Что такое Spring Boot Starter? Как использовать Starter в своем приложении? 82. Как настроить и использовать Spring Cloud Config Server для управления конфигурацией в приложении? 83. Какие принципы SOLID вы знаете и как они связаны с Spring Framework? 84. Как использовать Spring Test в тестировании приложений? 85. Какие подходы к реализации микросервисных архитектур вы знаете? Как их можно реализовать в Spring Framework? 86. Какие инструменты из экосистемы Spring можно использовать для мониторинга и управления приложениями? 87. Как организовать логирование в приложении, используя Spring Framework? 88. Как использовать Spring Security для аутентификации и авторизации пользователей в приложении? 89. Какие типы кэширования доступны в Spring Framework? Как их использовать? 90. Какие инструменты для профилирования и отладки приложений вы знаете? Как их использовать в разработке приложений на Spring Framework? 91. Что такое Spring Data REST? Как использовать Spring Data REST для создания RESTful API? 92. Как настроить и использовать Spring Cloud Netflix Eureka для реализации сервисной реестра в микросервисной архитектуре? 93. Какие виды транзакций поддерживает Spring Framework? Какие аннотации используются для управления транзакциями? 94. Что такое Spring WebFlux? Какие преимущества он предоставляет по сравнению с Spring MVC? 95. Как использовать Spring Cloud Gateway для реализации шлюза API? 96. Как работать с WebSocket в Spring Boot? 97. Как использовать Spring Cloud Sleuth для трассировки запросов в распределенных системах? 98. Какие инструменты доступны в экосистеме Spring для обмена сообщениями между сервисами? 99. Какие инструменты доступны в Spring Framework для работы с базами данных NoSQL? 100. Как использовать Spring Security для защиты приложения от атак на основе CSRF и XSS? 101. Как использовать Spring Batch для выполнения задач, выполняющихся в фоновом режиме? 102. Как работать с GraphQL в Spring Framework? 103. В чем преимущества Spring? 104. Что такое файл конфигурации для Spring? 105. Каковы различные модули Spring Framework? 106. Каковы различные компоненты приложения Spring? 107. Что такое внедрение зависимостей? 108. Что такое Spring IoK контейнер? 109. Каковы типы IoK? 110. Что такое Аспектно-ориентированное программирование (AOП)? 111. Что такое Spring Bean? 112. Каковы общие реализации ApplicationContext? 113. В чем разница между BeanFactory и ApplicationContext? 114. Как вы добавляете компонент в Spring? 115. Какие области Beans поддерживает Spring? 116. Каковы этапы жизненного цикла компонента? 117. Объясните внутреннюю часть bean в Spring 118. Что такое автоматическая проводка bean? 119. Как вы можете внедрить коллекции Java в Spring? 120. Что такое Joinpoint? 121. Что такое Advice в Spring? 122. Каковы типы рекомендаций для структуры Spring? 123. Что такое Weaving? 124. Опишите поддержку Spring DAO 125. Что такое JDBC? Какие классы присутствуют в API Spring JDBC? 126. Что такое платформа Spring Model-View-Controller (MVC)? 127. Каковы части фреймворка Spring MVC? 128. Каковы различные части DispatcherServlet? 129. Как можно включить проводку аннотаций в Spring? 130. Что такое Spring Boot? 131. Что такое Реактивное программирование? 132. Что такое Spring webflux? 133. В чем разница между веб-клиентом и клиентом веб-тестирования? 134. Может ли Spring Boot разрешить Spring MVC или Spring Web Flux в одном и том же приложении? 135. Может ли Spring 5 интегрироваться с модульностью Jdk9? 136. Расскажите о Spring Framework. 137. Какие некоторые из важных особенностей и преимуществ Spring Framework? 138. Что вы понимаете под Dependency Injection (DI)? 139. Как реализуется DI в Spring Framework? 140. Какие преимущества использования Spring Tool Suite? 141. Приведите названия некоторых важных Spring модулей. 142. Что вы понимаете под аспектно-ориентированным программированием (Aspect Oriented Programming — AOP)? 143. Что такое Aspect, Advice, Pointcut, JoinPoint и Advice Arguments в АОП? 144. В чем разница между Spring AOP и AspectJ АОП? 145. Что такое IoC контейнер Spring? 146. Что такое Spring бин? 147. Какое значение имеет конфигурационный файл Spring Bean? 148. Какие различные способы настроить класс как Spring Bean? 149. Какие вы знаете различные scope у Spring Bean? 150. Что такое жизненный цикл Spring Bean? 151. Как получить объекты ServletContext и ServletConfig внутри Spring Bean? 152. Что такое связывание в Spring и расскажите об аннотации @Autowired? 153. Какие различные типы автоматического связывания в Spring? 154. Является ли Spring бин потокобезопасным? 155. Что такое контроллер в Spring MVC? 156. Какая разница между аннотациями @Component, @Repository и @Service в Spring? 157. Расскажите, что вы знаете о DispatcherServlet и ContextLoaderListener. 158. Что такое ViewResolver в Spring? 159. Что такое MultipartResolver и когда его использовать? 160. Как обрабатывать исключения в Spring MVC Framework? 161. Как создать ApplicationContext в программе Java? 162. Можем ли мы иметь несколько файлов конфигурации Spring? 163. Какие минимальные настройки, чтобы создать приложение Spring MVC? 164. Как бы вы связали Spring MVC Framework и архитектуру MVC? 165. Как добиться локализации в приложениях Spring MVC? 166. Как мы можем использовать Spring для создания веб-службы RESTful, возвращающей JSON? 167. Приведите пример часто используемых аннотаций Spring. 168. Можем ли мы послать объект как ответ метода обработчика контроллера? 169. Как загрузить файл в Spring MVC? 170. Как проверить (валидировать) данные формы в Spring Web MVC Framework? 171. Что вы знаете Spring MVC Interceptor и как он используется? 172. Spring JdbcTemplate класс и его применение. 173. Как использовать Tomcat JNDI DataSource в веб-приложении Spring? 174. Каким образом можно управлять транзакциями в Spring? 175. Расскажите о Spring DAO. 176. Как интегрировать Spring и Hibernate? 177. Расскажите о Spring Security. 178. Как внедрить java.util.Properties в Spring Bean? 179. Назовите некоторые из шаблонов проектирования, используемых в Spring Framework? 180. Best Practices в Spring Framework. [Вопросы для собеседования](README.md) Про транзакции подробно: http://akorsa.ru/2016/08/kak-na-samom-dele-rabotaet-transactional-spring/ # SPRING - [Cобеседование по Java. Разбор вопросов и ответов.](#cобеседование-по-java-разбор-вопросов-и-ответов) - [SPRING](#spring) - [Что такое Spring](#что-такое-spring) - [Особенности и преимущества Spring Framework?](#особенности-и-преимущества-spring-framework) - [Spring контейнеры](#spring-контейнеры) - [Жизненный цикл Context](#жизненный-цикл-context) - [Как завершить работу контекста](#как-завершить-работу-контекста) - [Bean](#bean) - [Жизненный цикл бинов](#жизненный-цикл-бинов) - [Как настроить класс как Spring Bean](#как-настроить-класс-как-spring-bean) - [Статический Bean](#статический-bean) - [Inversion of Control](#inversion-of-control) - [Dependency Injection (DI)](#dependency-injection-di) - [Как реализуется DI в Spring Framework?](#как-реализуется-di-в-spring-framework) - [Связывание и @Autowired](#связывание-и-autowired) - [MVC](#mvc) - [Шаблон проектирования Front Controller](#шаблон-проектирования-front-controller) - [В чем разница между Filters, Listeners и Interceptors?](#в-чем-разница-между-filters-listeners-и-interceptors) - [Связывание форм](#связывание-форм) - [Исключения в Spring MVC](#исключения-в-spring-mvc) - [Локализация в приложениях Spring MVC](#локализация-в-приложениях-spring-mvc) - [Spring Interceptor](#spring-interceptor) - [CommandLineRunner и ApplicationRunner](#commandlinerunner-и-applicationrunner) - [Реактивное программирование](#реактивное-программирование) - [Паттерны в Spring Framework](#паттерны-в-spring-framework) - [AOP и составные части](#aop-и-составные-части) - [Spring AOP vs ASPECTJ](#spring-aop-vs-aspectj) - [Некоторые частые аннотации Spring](#некоторые-частые-аннотации-spring) - [Различия @Component, @Service, @Repository, @Controller](#различия-component-service-repository-controller) - [Различия @Controller и @RestController](#различия-controller-и-restcontroller) - [@Qualifier and @Primary](#qualifier-and-primary) - [@Profile](#profile) - [@LookUp](#lookup) - [@Target и @Retention](#target-и-retention) - [@Resource](#resource) - [@Inject](#inject) - [@Autowired vs @Resource vs @Inject](#autowired-vs-resource-vs-inject) - [@Conditional](#conditional) - [Как управлять транзакциями в Spring](#как-управлять-транзакциями-в-spring) - [новая инфа](#новая-инфа) - [старая инфа](#старая-инфа) - [Как Spring работает с DAO](#как-spring-работает-с-dao) - [Model vs ModelMap vs ModelAndView](#model-vs-modelmap-vs-modelandview) - [В чем разница между model.put() и model.addAttribute()?](#в-чем-разница-между-modelput-и-modeladdattribute) - [PreparedStatementCreator](#preparedstatementcreator) - [SOAP vs REST](#soap-vs-rest) - [Spring Data](#spring-data) - [Конфигурация Spring Data](#конфигурация-spring-data) - [Spring Security](#spring-security) - [Spring Boot](#spring-boot) - [Starter packs](#starter-packs) - [Как внедрить java.util.Properties в Spring Bean](#как-внедрить-javautilproperties-в-spring-bean) - [Что нового в Spring 5](#что-нового-в-spring-5) - [RestTemplate и JDBCTemplate](#resttemplate-и-jdbctemplate) - [Socket](#socket) ## Что такое Spring Spring - фреймворк с открытым исходным кодом, предназначеный для упрощения разработки enterprise-приложений. Одним из главным преимуществом Spring является его слоистая архитектура, позволяющая вам самим определять какие компоненты будут использованы в вашем приложении. Модули Spring построены на базе основного контейнера, который определяет создание, конфигурация и менеджмент бинов. Основные фраймворки внутри Springa: + Основной контейнер (Beans, Core, Context, SpEL) - предоставляет основной функционал Spring, управляющий процессом создания и настройки компонентов приложения. Beans отвечает за BeanFactory которая является сложной реализацией паттерна Фабрика (GoF). Модуль __Core__ обеспечивает ключевые части фреймворка, включая свойства IoC и DI. __Context__ построен на основе Beans и Core и позволяет получить доступ к любому объекту, который определён в настройках. Ключевым элементом модуля Context является интерфейс ApplicationContext. Модуль __SpEL__ обеспечивает мощный язык выражений для манипулирования объектами во время исполнения. В нем есть тернатрные, арефметические, логические операторы. Может получить доступ к элементам коллекций. + Spring AOP (AOP, Aspects) - отвечает за интеграцию аспектно-ориентированного программирования во фреймворк. Spring AOP обеспечивает сервис управления транзакциями для Spring-приложения. + Spring Data — дополнительный удобный механизм для взаимодействия с сущностями базы данных, организации их в репозитории, извлечение данных, изменение, в каких то случаях для этого будет достаточно объявить интерфейс и метод в нем, без имплементации. Например с использованием JPA. Состоит из JDBC, ORM, OXM, JMS и модуля Transatcions. JDBC обеспечивает абстрактный слой JDBC и избавляет разработчика от необходимости вручную прописывать монотонный код, связанный с соединением с БД. ORM обеспечивает интеграцию с такими популярными ORM, как Hibernate, JDO, JPA и т.д. Модуль OXM отвечает за связь Объект/XML – XMLBeans, JAXB и т.д. Модуль JMS (Java Messaging Service) отвечает за создание, передачу и получение сообщений. Transactions поддерживает управление транзакциями для классов, которые реализуют определённые методы. + Spring Web module (Web, Servlet, Portlet, Struts) - Модуль Web обеспечивает такие функции, как загрузка файлов и т.д. Web-MVC содержит реализацию Spring MVC для веб-приложений. Web-Socket обеспечивает поддержку связи между клиентом и сервером, используя Web-Socket-ы в веб-приложениях. Web-Portlet обеспечивает реализацию MVC с среде портлетов. + Spring MVC framework - реализация паттерна MVC для построения Web-приложений. + Spring Integration - обеспечивает легкий обмен сообщениями в приложениях на базе Spring и поддерживает интеграцию с внешними системами через декларативные адаптеры. Эти адаптеры обеспечивают более высокий уровень абстракции по сравнению с поддержкой Spring для удаленного взаимодействия, обмена сообщениями и планирования. Основная цель Spring Integration - предоставить простую модель для построения корпоративных решений по интеграции, сохраняя при этом разделение задач, что важно для создания поддерживаемого, тестируемого кода. + Spring Cloud - инструменты для создания сложных топологий для потоковой и пакетной передачи данных. + Spring Batch - предоставляет многократно используемые функции, которые необходимы для обработки больших объемов записей, включая ведение журнала / трассировку, управление транзакциями, статистику обработки заданий, перезапуск заданий, пропуск и управление ресурсами. Он также предоставляет более продвинутые технические услуги и функции, которые позволят выполнять пакетные задания чрезвычайно большого объема и с высокой производительностью благодаря методам оптимизации и разделения. Простые и сложные пакетные задания большого объема могут использовать платформу с высокой степенью масштабируемости для обработки значительных объемов информации. + Spring Kafka - Проект Spring for Apache Kafka (spring-kafka) применяет основные концепции Spring для разработки решений для обмена сообщениями на основе Kafka. Он предоставляет «шаблон» в качестве высокоуровневой абстракции для отправки сообщений. Он также обеспечивает поддержку управляемых сообщениями POJO с @KafkaListener аннотациями и «контейнером слушателя». Эти библиотеки способствуют использованию инъекций зависимостей и декларативных. Во всех этих случаях вы увидите сходство с поддержкой JMS в Spring Framework и поддержкой RabbitMQ в Spring AMQP. + Spring Security - Фреймворк аутентификации и авторизации: конфигурируемый инструментарий процессов аутентификации и авторизации, поддерживающий много популярных и ставших индустриальными стандартами протоколов, инструментов, практик. + Тестирование - каркас, поддерживающий классы для написания модульных и интеграционных тестов. [к оглавлению](#spring) ## Особенности и преимущества Spring Framework? Spring Framework обеспечивает решения многих задач, с которыми сталкиваются Java-разработчики и организации, которые хотят создать информационную систему, основанную на платформе Java. Из-за широкой функциональности трудно определить наиболее значимые структурные элементы, из которых он состоит. Spring Framework не всецело связан с платформой Java Enterprise, несмотря на его масштабную интеграцию с ней, что является важной причиной его популярности. Spring Framework, вероятно, наиболее известен как источник расширений (features), нужных для эффективной разработки сложных бизнес-приложений вне тяжеловесных программных моделей, которые исторически были доминирующими в промышленности. Ещё одно его достоинство в том, что он ввел ранее неиспользуемые функциональные возможности в сегодняшние господствующие методы разработки, даже вне платформы Java. Этот фреймворк предлагает последовательную модель и делает её применимой к большинству типов приложений, которые уже созданы на основе платформы Java. Считается, что Spring Framework реализует модель разработки, основанную на лучших стандартах индустрии, и делает её доступной во многих областях Java. Таким образом к достоинствам Spring можно отнести: + Относительная легкость в изучении и применении фреймворка в разработке и поддержке приложения. + Внедрение зависимостей (DI) и инверсия управления (IoC) позволяют писать независимые друг от друга компоненты, что дает преимущества в командной разработке, переносимости модулей и т.д.. + Spring IoC контейнер управляет жизненным циклом Spring Bean и настраивается наподобие JNDI lookup (поиска). + Проект Spring содержит в себе множество подпроектов, которые затрагивают важные части создания софта, такие как вебсервисы, веб программирование, работа с базами данных, загрузка файлов, обработка ошибок и многое другое. Всё это настраивается в едином формате и упрощает поддержку приложения. ## Spring контейнеры Container создаёт объекты, связывает их вместе, настраивает и управляет ими от создания до момента уничтожения. Spring Container получает инструкции какие объекты инстанциировать и как их конфигурировать через метаданные: __XML, Аннотации или Java код__ . __Spring BeanFactory Container__ Это самый простой контейнер, который обеспечивает базовую поддержку DI и который основан на интерфейсе org.springframework.beans.factory.BeanFactory. Такие интерфейсы, как BeanFactoryAware и DisposableBean всё ещё присутствуют в Spring для обеспечения обратной совместимости. Бины создаются при вызове метода getBean(). Наиболее часто используемая реализация интерфейса BeanFactory – XmlBeanFactory. XmlBeanFactory получает метаданные из конфигурационного XML файла и использует его для создания настроенного приложения или системы. BeanFactory обычно используется тогда, когда ресурсы ограничены (мобильные устройства). Поэтому, если ресурсы не сильно ограничены, то лучше использовать ApplicationContext. __Spring ApplicationContext Container__ ApplicationContext является более сложным и более продвинутым Spring Container-ом. Наследует BeanFactory и так же загружает бины, связывает их вместе и конфигурирует их определённым образом. Но кроме этого, ApplicationContext обладает дополнительной функциональностью: общий механизм работы с ресурсами, распознание текстовых сообщений из файлов настройки и отображение событий, которые происходят в приложении различными способами. Этот контейнер определяется интерфейсом org.springframework.context.ApplicationContext. Бины создаются при "поднятии" контекста все сразу. Если не указана стратегия инициализации. Чаще всего используются следующие реализации AppicationContext: + FileSystemXmlApplicationContext - Загружает данные о бине из XML файла. При использовании этой реализации в конструкторе необходимо указать полный адрес конфигурационного файла. + ClassPathXmlApplicationContext - Этот контейнер также получает данные о бине из XML файла. Но в отличие от FileSystemApplicationContext, в этом случае необходимо указать относительный адрес конфигурационного файла (CLASSPATH). + AnnotationConfigApplicationContext — метаданные конфигурируются с помощью аннотаций прямо на классах. + WebApplicationContext — для веб-приложений + GenericGroovyApplicationContext - эта конфигурация работает по сути так же, как и Xml, только с Groovy-файлами. К тому же, GroovyApplicationContext нормально работает и с Xml-файлом. Принимает на вход строку с конфигурацией контекста. Чтением контекста в данном случае занимается класс GroovyBeanDefinitionReader. Groovy — объектно-ориентированный язык программирования разработанный для платформы Java как альтернатива языку Java с возможностями Python, Ruby и Smalltalk. Groovy использует Java-подобный синтаксис с динамической компиляцией в JVM байт-код и напрямую работает с другим Java кодом и библиотеками. Язык может использоваться в любом Java проекте или как скриптовый язык. При этом мы можем указать несколько файлов конфигурации Spring. Отличия ApplicationContext и BeanFactory 1. ApplicationContext загружает все бины при запуске, а BeanFactory - по требованию. 2. ApplicationContext расширяет BeanFactory и предоставляет функции, которые подходят для корпоративных приложений: a. поддержка внедрения зависимостей на основе аннотаций; b. удобный доступ к MessageSource (для использования в интернационализации); c. публикация ApplicationEvent - для бинов, реализующих интерфейс ApplicationListener, с помощью интерфейса ApplicationEventPublisher; d. простая интеграция с функциями Spring AOP. 3. ApplicationContext поддерживает автоматическую регистрацию BeanPostProcessor и BeanFactoryPostProcessor. Поэтому всегда желательно использовать ApplicationContext, потому что Spring 2.0 (и выше) интенсивно использует BeanPostProcessor. 4. ApplicationContext поддерживает практически все типы scope для бинов, а BeanFactory поддерживает только два - Singleton и Prototype. 5. В BeanFactory не будут работать транзакции и Spring AOP. Это может привести к путанице, потому что конфигурация с виду будет корректной ## Жизненный цикл Context + Контейнер создается при запуске приложения + Контейнер считывает конфигурационные данные (парсинг XML, JavaConfig) + Из конфигурационных данных создается описание бинов (BeanDafinition) BeanDefenitionReader + BeanFactoryPostProcessors обрабатывают описание бина + Контейнер создает бины используя их описание + Бины инициализируются — значения свойств и зависимости внедряются в бин (настраиваются) + BeanPostProcessor запускают методы обратного вызова(callback methods) + Приложение запущено и работает + Инициализируется закрытие приложения + Контейнер закрывается + Вызываются callback methods https://habr.com/ru/post/222579/ ## Как завершить работу контекста Если это не веб-приложение, то есть 2 способа: + Регистрация shutdown-hook с помощью вызова метода registerShutdownHook(), он также реализован в классе AbstractApplicationContext. Это предпочтительный способ. + Можно вызвать метод close() из класса AbstractApplicationContext. В Spring Boot приложении: Spring Boot самостоятельно зарегистрирует shutdown-hook за вас. ## Bean Бин (bean) — это не что иное, как самый обычный объект. Разница лишь в том, что бинами принято называть те объекты, которые управляются Spring-ом и живут внутри его DI-контейнера. По умолчанию бин задается как синглтон в Spring. Таким образом все публичные переменные класса могут быть изменены одновременно из разных мест, а значит бин - не потокобезопасен. Однако поменяв область действия бина на request, prototype, session он станет потокобезопасным, но это скажется на производительности. Конфигурационный файл спринг определяет все бины, которые будут инициализированы в Spring Context. При создании экземпляра Spring ApplicationContext будет прочитан конфигурационный xml файл и выполнены указанные в нем необходимые инициализации. Отдельно от базовой конфигурации, в файле могут содержаться описание перехватчиков (interceptors), view resolvers, настройки локализации и др. Определение бина содержит метаданные конфигурации, которые необходимы управляющему контейнеру для получения следующей информации: Как создать бин; Информацию о жизненном цикле бина; Зависимости бина. В Spring Framework существуют такие свойства, определяющие бины: + class - Этот атрибут является обязательным и указывает конкретный класс Java-приложения, который будет использоваться для создания бина. + name - Уникальный идентификатор бина. В случае конфигурации с помощью xml-файла, вы можете использовать свойство “id” и/или “name” для идентификации бина. Атрибут name также может принимать массив String, что позволяет использовать несколько имен. Первый элемент массива будет являться именем и уникальным идентификатором бина, а остальные будут его псевдонимами. + scope - Это свойство определяет область видимости создаваемых объектов. - __singleton__ - Определяет один единственный бин для каждого контейнера Spring IoC (используется по умолчанию); - __prototype__ - контейнер Spring IoC создаёт новый экземпляр бина на каждый полученный запрос т.е. иметь любое количество экземпляров бина; - __request__ - Создаётся один экземпляр бина на каждый HTTP запрос. Касается исключительно ApplicationContext; - __session__ - Создаётся один экземпляр бина на каждую HTTP сессию. Касается исключительно ApplicationContext; - __web soccet__ - Создаётся один экземпляр бина для определенного сокета. - __application__ - Создаётся один экземпляр бина для жизненного цикла бина. Похоже на синглтон, но когда бобы ограничены областью приложения, значения, однажды установленное в applicationScopedBean, будет сохранено для всех последующих запросов, сеансов и даже для другого приложения сервлета, которое будет обращаться к этому Бобу, при условии, что оно выполняется в том же ServletContext. В то время как одноэлементные бобы ограничены только одним контекстом приложения. + constructor-arg - Определяет конструктор, использующийся для внедрения зависимости. Более подробно – далее. + properties - Определяет свойства внедрения зависимости. Более подробно рассмотрим далее. + initialization method - Здесь определяется метод инициализации бина + destruction method - Метод уничтожения бина, который будет использоваться при уничтожении контейнера, содержащего бин. + autowiring mode - Определяет режим автоматического связывания при внедрении зависимости. Более подробно рассмотрим далее. + lazy-initialization mode - Режим ленивой инициализации даёт контейнеру IoC команду создавать экземпляр бина при первом запросе, а не при запуске приложения. Классы, аннотированные @Configuration, проксируются через CGLIB. Классы @Component или обычные классы не проксируются и не перехватывают вызовы методов с аннотациями @Bean, что означает, что вызовы не будут маршрутизироваться через контейнер и каждый раз будет возвращаться новый экземпляр бина. CGLIB (Code Generation Library) - Это библиотека инструментария байтов, используемая во многих средах Java, таких как Hibernate или Spring. Инструментарий байт-кода позволяет манипулировать или создавать классы после фазы компиляции программы. __Жизненный цикл бинов:__ + Загрузка описаний бинов, создание графа зависимостей(между бинами) + Создание и запуск BeanFactoryPostProcessors + Создание бинов + Spring внедряет значения и зависимости в свойства бина + Если бин реализует метод setBeanName() из интерфейса NameBeanAware, то ID бина передается в метод + Если бин реализует BeanFactoryAware, то Spring устанавливает ссылку на bean factory через setBeanFactory() из этого интерфейса. + Если бин реализует интерфейс ApplicationContextAware, то Spring устанавливает ссылку на ApplicationContext через setApplicationContext(). + BeanPostProcessor это специальный интерфейс, и Spring позволяет бинам имплементировать этот интерфейс. Реализуя метод postProcessBeforeInitialization(), можно изменить экземпляр бина перед его(бина) инициализацией(установка свойств и т.п.) + Если определены методы обратного вызова, то Spring вызывает их. Например, это метод, аннотированный @PostConstruct или метод initMethod из аннотации @Bean. + Теперь бин готов к использованию. Его можно получить с помощью метода ApplicationContext#getBean(). + После того как контекст будет закрыт(метод close() из ApplicationContext), бин уничтожается. + Если в бине есть метод, аннотированный @PreDestroy, то перед уничтожением вызовется этот метод. Если бин имплементирует DisposibleBean, то Spring вызовет метод destroy(), чтобы очистить ресурсы или убить процессы в приложении. Если в аннотации @Bean определен метод destroyMethod, то вызовется и он. Интерфейс BeanPostProcessor позволяют разработчику самому имплементировать некоторые методы бинов перед инициализацией и после уничтожения экземпляров бина. Имеется возможность настраивать несколько имлементаций BeanPostProcessor и определить порядок их выполнения. Данный интерфейс работает с экземплярами бинов, а это означает, что Spring IoC создаёт экземпляр бина, а затем BeanPostProcessor с ним работает. ApplicationContext автоматически обнаруживает любые бины, с реализацией BeanPostProcessor и помечает их как “post-processors” для того, чтобы создать их определённым способом. Интерфейс BeanPostProcessor имеет всего два метода: postProcessBeforeInitialization и postProcessAfterInitialization ## Жизненный цикл бинов 1. __Парсирование конфигурации и создание BeanDefinition__ Цель первого этапа — это создание всех BeanDefinition. Объекты BeanDefinition — это набор метаданных будущего бина, макет, по которому нужно будет создавать бин в случае необходимости. То есть для каждого бина создается свой объект BeanDefinition, в котором хранится описание того, как создавать и управлять этим конкретным бином. Проще говоря, сколько бинов в программе - столько и объектов BeanDefinition, их описывающих. BeanDefinition содержат (среди прочего) следующие метаданные: - Имя класса с указанием пакета: обычно это фактический класс бина. - Элементы поведенческой конфигурации бина, которые определяют, как бин должен вести себя в контейнере (scope, обратные вызовы жизненного цикла и т.д.). - Ссылки на другие bean-компоненты, которые необходимы для его работы. Эти ссылки также называются зависимостями. - Другие параметры конфигурации для установки во вновь созданном объекте - например, ограничение размера пула или количество соединений, используемых в бине, который управляет пулом соединений. Эти метаданные преобразуются в набор свойств, которые составляют каждое BeanDefinition. В следующей таблице описаны эти свойства: При конфигурации через аннотации с указанием пакета для сканирования или JavaConfig используется класс AnnotationConfigApplicationContext. Регистрируются все классы с @Configuration для дальнейшего парсирования, затем регистрируется специальный BeanFactoryPostProcessor, а именно BeanDefinitionRegistryPostProcessor, который при помощи класса ConfigurationClassParser парсирует JavaConfig, загружает описания бинов (BeanDefinition), создаёт граф зависимостей (между бинами) и создаёт: ```java Map beanDefinitionMap = new ConcurrentHashMap<>(256); ``` в которой хранятся все описания бинов, обнаруженных в ходе парсинга конфигурации. 2. __Настройка созданных BeanDefinition__ После первого этапа у нас имеется коллекция Map, в которой хранятся BeanDefinition-ы. BeanFactoryPostProcessor-ы на этапе создания BeanDefinition-ов могут их настроить как нам необходимо. BeanFactoryPostProcessor-ы могут даже настроить саму BeanFactory ещё до того, как она начнет работу по созданию бинов. В интерфейсе BeanFactoryPostProcessor всего один метод: ```java public interface BeanFactoryPostProcessor { void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException; } ``` 3. __Создание кастомных FactoryBean (только для XML-конфигурации)__ 4. __Создание экземпляров бинов__ Сначала BeanFactory из коллекции Map с объектами BeanDefinition достаёт те из них, из которых создаёт все BeanPostProcessor-ы, необходимые для настройки обычных бинов. Создаются экземпляры бинов через BeanFactory на основе ранее созданных BeanDefinition 5. __Настройка созданных бинов__ На данном этапе бины уже созданы, мы можем лишь их донастроить. Интерфейс BeanPostProcessor позволяет вклиниться в процесс настройки наших бинов до того, как они попадут в контейнер. ApplicationContext автоматически обнаруживает любые бины с реализацией BeanPostProcessor и помечает их как “post-processors” для того, чтобы создать их определенным способом. Например, в Spring есть реализации BeanPostProcessor-ов, которые обрабатывают аннотации @Autowired, @Inject, @Value и @Resource. Интерфейс несет в себе два метода: postProcessBeforeInitialization(Object bean, String beanName) и postProcessAfterInitialization(Object bean, String beanName). У обоих методов параметры абсолютно одинаковые. Разница только в порядке их вызова. Первый вызывается до init-метода, второй - после. Как правило, BeanPostProcessor-ы, которые заполняют бины через маркерные интерфейсы или тому подобное, реализовывают метод postProcessBeforeInitialization (Object bean, String beanName), тогда как BeanPostProcessor-ы, которые оборачивают бины в прокси, обычно реализуют postProcessAfterInitialization (Object bean, String beanName). Прокси — это класс-декорация над бином. Например, мы хотим добавить логику нашему бину, но джава-код уже скомпилирован, поэтому нам нужно на лету сгенерировать новый класс. Этим классом мы должны заменить оригинальный класс так, чтобы никто не заметил подмены. Есть два варианта создания этого класса: - либо он должен наследоваться от оригинального класса (CGLIB) и переопределять его методы, добавляя нужную логику; - либо он должен имплементировать те же самые интерфейсы, что и первый класс(Dynamic Proxy). По конвенции спринга, если какой-то из BeanPostProcessor-ов меняет что-то в классе, то он должен это делать на этапе postProcessAfterInitialization(). Таким образом мы уверены, что initMethod у данного бина, работает на оригинальный метод, до того, как на него накрутился прокси. Хронология событий: 1. Сначала сработает метод postProcessBeforeInitialization() всех имеющихся BeanPostProcessor-ов. 2. Затем, при наличии, будет вызван метод, аннотированный @PostConstruct. 3. Если бин имплементирует InitializingBean, то Spring вызовет метод afterPropertiesSet() - не рекомендуется к использованию как устаревший. 4. При наличии, будет вызван метод, указанный в параметре initMethod аннотации @Bean. 5. В конце бины пройдут через postProcessAfterInitialization (Object bean, String beanName). Именно на данном этапе создаются прокси стандартными BeanPostProcessor-ами. Затем отработают наши кастомные BeanPostProcessor-ы и применят нашу логику к прокси-объектам. После чего все бины окажутся в контейнере, который будет обязательно обновлен методом refresh(). 6. Но даже после этого мы можем донастроить наши бины ApplicationListener-ами. 7. Теперь всё ![Image alt](https://github.com/Shell26/Java-Developer/raw/master/img/Spring1.png) 6. __Бины готовы к использованию__ Их можно получить с помощью метода ApplicationContext#getBean(). 8. __Закрытие контекста__ Когда контекст закрывается (метод close() из ApplicationContext), бин уничтожается. Если в бине есть метод, аннотированный @PreDestroy, то перед уничтожением вызовется этот метод. Если бин имплементирует DisposibleBean, то Spring вызовет метод destroy() - не рекомендуется к использованию как устаревший. Если в аннотации @Bean определен метод destroyMethod, то будет вызван и он. __@PostConstruct__ Spring вызывает методы, аннотированные @PostConstruct, только один раз, сразу после инициализации свойств компонента. За данную аннотацию отвечает один из BeanPostProcessor-ов. Метод, аннотированный @PostConstruct, может иметь любой уровень доступа, может иметь любой тип возвращаемого значения (хотя тип возвращаемого значения игнорируется Spring-ом), метод не должен принимать аргументы. Он также может быть статическим, но преимуществ такого использования метода нет, т.к. доступ у него будет только к статическим полям/методам бина, и в таком случае смысл его использования для настройки бина пропадает. Одним из примеров использования @PostConstruct является заполнение базы данных. Например, во время разработки нам может потребоваться создать пользователей по умолчанию. __@PreDestroy__ Метод, аннотированный @PreDestroy, запускается только один раз, непосредственно перед тем, как Spring удаляет наш компонент из контекста приложения. Как и в случае с @PostConstruct, методы, аннотированные @PreDestroy, могут иметь любой уровень доступа, но не могут быть статическими. Целью этого метода может быть освобождение ресурсов или выполнение любых других задач очистки до уничтожения бина, например, закрытие соединения с базой данных. Обратите внимание, что аннотации @PostConstruct и @PreDestroy являются частью Java EE, а именно пакета javax.annotation модуля java.xml.ws.annotation. И поскольку Java EE устарела в Java 9, то с этой версии пакет считается устаревшим (Deprecated). С Java 11 данный пакет вообще удален, поэтому мы должны добавить дополнительную зависимость для использования этих аннотаций: ```java javax.annotation javax.annotation-api 1.3.2 ``` ## Как настроить класс как Spring Bean 1) XML конфигурация ```java ``` 2) Java code - все настройки прописываются непосредственно в коде ```java @configuration @ComponentScan(value="project.spring.main") public class MyConfiguration [ @Bean public MyService getService() { return new MyService(); } } ``` Для извлечения бина: ```java AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(MyConfiguration.class); MyService service = ctx.getBean(MyService.class); ``` 3) Annotation - внутри кода используются аннотации @Component, @Service, @Repository, @Controller для указания классов как бины. Для их поиска и управления контейнером прописывается настройка в xml файле ```java ``` ## Статический Bean Если в классе будет статический метод, то при инициализации впервую очередь создастся статический метод (из-за особенностей статических полей), а потом уже Bean, который "навешивается" на статический метод. При этом Spring не позволяет внедрять бины напрямую в статические поля, нужно создать нестатический сеттер-метод ```java @Component public class TestDataInit { @Autowired private static OrderItemService orderItemService; //будет null } @Component public class TestDataInit { private static OrderItemService orderItemService; @Autowired public void setOrderItemService(OrderItemService orderItemService) { TestDataInit.orderItemService = orderItemService; } } ``` [к оглавлению](#spring) ## Inversion of Control Центральной частью Spring является подход Inversion of Control, который позволяет конфигурировать и управлять объектами Java с помощью рефлексии. Вместо ручного внедрения зависимостей, фреймворк забирает ответственность за это посредством контейнера. Контейнер отвечает за управление жизненным циклом объекта: создание объектов, вызов методов инициализации и конфигурирование объектов путём связывания их между собой. Объекты, создаваемые контейнером, также называются управляемыми объектами (beans). Обычно, конфигурирование контейнера, осуществляется путём внедрения аннотаций (начиная с 5 версии J2SE), но также, есть возможность, по старинке, загрузить XML-файлы, содержащие определение bean’ов и предоставляющие информацию, необходимую для создания bean’ов. Плюсы такого подхода: - отделение выполнения задачи от ее реализации; - легкое переключение между различными реализациями; - большая модульность программы; - более легкое тестирование программы путем изоляции компонента или проверки его зависимостей и обеспечения взаимодействия компонентов через контракты. Объекты могут быть получены одним из двух способов: __Dependency Lookup Поиск зависимости__ — шаблон проектирования, в котором вызывающий объект запрашивает у объекта-контейнера экземпляр объекта с определённым именем или определённого типа. __Dependency Injection Внедрение зависимости__ — шаблон проектирования, в котором контейнер передает экземпляры объектов по их имени другим объектам с помощью конструктора, свойства или фабричного метода. ## Dependency Injection (DI) Под DI понимают то __Dependency Inversion__ (инверсию зависимостей, то есть попытки не делать жестких связей между вашими модулями/классами, где один класс напрямую завязан на другой), то __Dependency Injection__ (внедрение зависимостей, это когда объекты котиков создаете не вы в main-е и потом передаете их в свои методы, а за вас их создает спринг, а вы ему просто говорите что-то типа "хочу сюда получить котика" и он вам его передает в ваш метод). Мы чаще будем сталкиваться в дальнейших статьях со вторым. Внедрение зависимости (Dependency injection, DI) — процесс, когда один объект реализует свой функционал через другой. Является специфичной формой «инверсии управления» (Inversion of control, IoC), когда она применяется к управлению зависимостями. В полном соответствии с принципом единой обязанности объект отдаёт заботу о построении требуемых ему зависимостей внешнему, специально предназначенному для этого общему механизму. К достоинствам применения DI можно отнести: + Сокращение объема связующего кода. Одним из самых больших плюсов DI является возможность значительного сокращения объема кода, который должен быть написан для связывания вместе различных компонентов приложения. Зачастую этот код очень прост — при создании зависимости должен создаваться новый экземпляр соответствующего объекта. + Упрощенная конфигурация приложения. За счет применения DI процесс конфигурирования приложения значительно упрощается. Для конфигурирования классов, которые могут быть внедрены в другие классы, можно использовать аннотации или XML-файлы. + Возможность управления общими зависимостями в единственном репозитории. При традиционном подходе к управлению зависимостями в общих службах, к которым относятся, например, подключение к источнику данных, транзакция, удаленные службы и т.п., вы создаете экземпляры (или получаете их из определенных фабричных классов) зависимостей там, где они нужны — внутри зависимого класса. Это приводит к распространению зависимостей по множеству классов в приложении, что может затруднить их изменение. В случае использования DI вся информация об общих зависимостях содержится в единственном репозитории (в Spring есть возможность хранить эту информацию в XML-файлах или Java классах), что существенно упрощает управление зависимостями и снижает количество возможных ошибок. + Улучшенная возможность тестирования. Когда классы проектируются для DI, становится возможной простая замена зависимостей. Это особенно полезно при тестировании приложения. + Стимулирование качественных проектных решений для приложений. Вообще говоря, проектирование для DI означает проектирование с использованием интерфейсов. Используя Spring, вы получаете в свое распоряжение целый ряд средств DI и можете сосредоточиться на построении логики приложения, а не на поддерживающей DI платформе. ## Как реализуется DI в Spring Framework? Реализация DI в Spring основана на двух ключевых концепциях Java — компонентах JavaBean и интерфейсах. При использовании Spring в качестве поставщика DI вы получаете гибкость определения конфигурации зависимостей внутри своих приложений разнообразными путями (т.е. внешне в XML-файлах, с помощью конфигурационных Java классов Spring или посредством аннотаций Java в коде). Компоненты JavaBean (также называемые POJO (Plain Old Java Object — простой старый объект Java)) предоставляют стандартный механизм для создания ресурсов Java, которые являются конфигурируемыми множеством способов. За счет применения DI объем кода, который необходим при проектировании приложения на основе интерфейсов, снижается почти до нуля. Кроме того, с помощью интерфейсов можно получить максимальную отдачу от DI, потому что бины могут использовать любую реализацию интерфейса для удовлетворения их зависимости. К типам реализации внедрения зависимостей в Spring относят: Constructor Dependency Injection — это тип внедрения зависимостей, при котором зависимости компонента предоставляются ему в его конструкторе (или конструкторах). Рекомендуется как основной способ, т.к. даже без спринга внедрение зависимостей будет работать корректно. ```java public class ConstructorInjection { private Dependency dependency; public ConstructorInjection(Dependency dependency) { this.dependency = dependency; } } ``` Setter Dependency Injection — контейнер IoC внедряет зависимости компонента в компонент через методы установки в стиле JavaBean. В основном через сеттеры. При модификации не создает новые экземпляры, в отличии от конструктора. Он при каждой модификации создаёт новый экземпляр. ```java public class SetterInjection { private Dependency dependency; public void setDependency(Dependency dependency) { this.dependency = dependency; } } ``` ## Связывание и @Autowired Процесс внедрения зависимостей в бины при инициализации называется Spring Bean Wiring. Считается хорошей практикой задавать явные связи между зависимостями, но в Spring предусмотрен дополнительный механизм связывания @Autowired. Аннотация может использоваться над конструктор, поле, сеттер-метод или метод конфигурации для связывания по типу. Если в контейнере не будет обнаружен необходимый для вставки бин, то будет выброшено исключение, либо можно указать @Autowired(required = false), означающее, что внедрение зависимости в данном месте не обязательно. Чтобы аннотация заработала, необходимо указать небольшие настройки в конфигурационном файле спринг с помощью элемента . Типы связывания: + autowire byName, + autowire byType, + autowire by constructor, + autowiring by @Autowired and @Qualifier annotations Начиная со Spring Framework 4.3, аннотация @Autowired для конструктора больше не требуется, если целевой компонент определяет только один конструктор. Однако, если доступно несколько конструкторов и нет основного/стандартного конструктора, по крайней мере один из конструкторов должен быть аннотирован @Autowired, чтобы указать контейнеру, какой из них использовать. Мы также можем указать Spring предоставить все бины определенного типа из ApplicationContext, добавив аннотацию @Autowired в поле или метод с массивом или коллекцией этого типа, как показано в следующем примере: ```java @Autowired private MovieCatalog[] movieCatalogs; или: @Autowired private Set movieCatalogs; или: @Autowired public void setMovieCatalogs(Set movieCatalogs) { this.movieCatalogs = movieCatalogs; } ``` Даже коллекции типа Map могут быть подключены автоматически, если тип ключа - String. Ключами будут имена бинов, а значениями - сами бины, как показано в следующем примере: ```java public class MovieRecommender { private Map movieCatalogs; @Autowired public void setMovieCatalogs(Map movieCatalogs){ this.movieCatalogs = movieCatalogs; } // ... } ``` [к оглавлению](#spring) ## MVC Spring имеет собственную MVC-платформу веб-приложений, которая не была первоначально запланирована. Spring MVC является фреймворком, ориентированным на запросы. В нем определены стратегические интерфейсы для всех функций современной запросно-ориентированной системы. Цель каждого интерфейса — быть простым и ясным, чтобы пользователям было легко его заново имплементировать, если они того пожелают. MVC прокладывает путь к более чистому front-end-коду. Все интерфейсы тесно связаны с Servlet API. Эта связь рассматривается некоторыми как неспособность разработчиков Spring предложить для веб-приложений абстракцию более высокого уровня. Однако эта связь оставляет особенности Servlet API доступными для разработчиков, облегчая все же работу с ним. Наиболее важные интерфейсы, определенные Spring MVC, перечислены ниже: __HandlerMapping__: выбор класса и его метода, которые должны обработать данный входящий запрос на основе любого внутреннего или внешнего для этого запроса атрибута или состояния. __HandlerAdapter__: вызов и выполнение выбранного метода обработки входящего запроса. __Controller__: включен между Моделью (Model) и Представлением (View). Управляет процессом преобразования входящих запросов в адекватные ответы. Действует как ворота, направляющие всю поступающую информацию. Переключает поток информации из модели в представление и обратно. Класс DispatcherServlet является главным контроллером, которые получает запросы и распределяет их между другими контроллерами. @RequestsMapping указывает, какие именно запросы будут обрабатываться в конкретном контроллере. Может быть несколько экземпляров DispatcherServlet, отвечающих за разные задачи (обработка запросов пользовательского интерфейса, REST служб и т.д.). Каждый экземпляр DispatcherServlet имеет собственную конфигурацию WebApplicationContext, которая определяет характеристики уровня сервлета, такие как контроллеры, поддерживающие сервлет, отображение обработчиков, распознавание представлений, интернационализация, оформление темами, проверка достоверности, преобразование типов и форматирование и т.п. ContextLoaderListener - слушатель при старте и завершении корневого класса Spring WebApplicationContext. Основным назначением является связывание жизненного цикла ApplicationContext и ServletContext, а так же автоматического создания ApplicationContext. Можно использовать этот класс для доступа к бинам из различных контекстов спринг. Настраивается в web.xml __Model__: Этот блок инкапсулирует (объединяет) данные приложения. На практике это POJO-классы. __View__: ответственно за возвращение ответа клиенту в виде текстов и изображений. Некоторые запросы могут идти прямо во View, не заходя в Model; другие проходят через все три слоя. __ViewResolver__: выбор, какое именно View должно быть показано клиенту. Поддерживает распознавание представлений на основе логического имени, возвращаемого контроллером. Для поддержки различных механизмов распознавания представлений предусмотрено множество классов реализации. Например, класс UrlBasedViewResolver поддерживает прямое преобразование логических имен в URL. Класс ContentNegotiatingViewResolver поддерживает динамическое распознавание представлений в зависимости от типа медиа, поддерживаемого клиентом (XML, PDF, JSON и т.д.). Существует также несколько реализаций для интеграции с различными технологиями представлений, такими как FreeMarker (FreeMarkerViewResolver), Velocity (VelocityViewResolver) и JasperReports (JasperReportsViewResolver). __HandlerInterceptor__: перехват входящих запросов. Сопоставим, но не эквивалентен сервлет-фильтрам (использование не является обязательным и не контролируется DispatcherServlet-ом). __LocaleResolver__: получение и, возможно, сохранение локальных настроек (язык, страна, часовой пояс) пользователя. __MultipartResolver__: обеспечивает Upload — загрузку на сервер локальных файлов клиента. По умолчанию этот интерфейс не включается в приложении и необходимо указывать его в файле конфигурации. После настройки любой запрос о загрузке будет отправляться этому интерфейсу. Spring MVC предоставляет разработчику следующие возможности: + Ясное и прозрачное разделение между слоями в MVC и запросах. + Стратегия интерфейсов — каждый интерфейс делает только свою часть работы. + Интерфейс всегда может быть заменен альтернативной реализацией. + Интерфейсы тесно связаны с Servlet API. + Высокий уровень абстракции для веб-приложений. + В веб-приложениях можно использовать различные части Spring, а не только Spring MVC. ![Image alt](https://github.com/Shell26/Java-Developer/raw/master/img/Spring2.png) ## Шаблон проектирования Front Controller Паттерн Front Controller обеспечивает единую точку входа для всех входящих запросов. Все запросы обрабатываются одним фрагментом кода, который затем может делегировать ответственность за обработку запроса другим объектам приложения. Он также обеспечивает интерфейс для общего поведения, такого как безопасность, интернационализация и передача определенных представлений определенным пользователям. В Spring в качестве Front Controller выступает DispatcherServlet, все действия проходят через него. Как правило в приложении задаётся только один DispatcherServlet с маппингом “/”, который перехватывает все запросы. Это и есть реализация паттерна Front Controller. Однако иногда необходимо определить два и более DispatcherServlet-а, которые будут отвечать за свой собственный функционал. Например, чтобы один обрабатывал REST-запросы с маппингом “/api”, а другой обычные запросы с маппингом “/default”. Spring предоставляет нам такую возможность, и для начала нужно понять, что: - Spring может иметь несколько контекстов одновременно. Одним из них будет корневой контекст, а все остальные контексты будут дочерними. - Все дочерние контексты могут получить доступ к бинам, определенным в корневом контексте, но не наоборот. Корневой контекст не может получить доступ к бинам дочерних контекстов. - Каждый дочерний контекст внутри себя может переопределить бины из корневого контекста. Каждый DispatcherServlet имеет свой дочерний контекст приложения. DispatcherServlet по сути является сервлетом(он расширяет HttpServlet), основной целью которого является обработка входящих вебзапросов, соответствующих настроенному шаблону URL. Он принимает входящий URI и находит правильную комбинацию контроллера и вида. Веб-приложение может определять любое количество DispatcherServlet-ов. Каждый из них будет работать в своем собственном пространстве имен, загружая свой собственный дочерний WebApplicationContext (на рисунке - Servlet WebApplicationContext) с вьюшками, контроллерами и т.д. Например, когда нам нужно в одном Servlet WebApplicationContext определить обычные контроллеры, а в другом REST-контроллеры. ![Image alt](https://github.com/Shell26/Java-Developer/raw/master/img/Spring3.png) WebApplicationContext расширяет ApplicationContext (создаёт и управляет бинами и т.д.), но помимо этого он имеет дополнительный метод getServletContext(), через который у него есть возможность получать доступ к ServletContext-у. ContextLoaderListener создает корневой контекст приложения (на рисунке - Root WebApplicationContext) и будет использоваться всеми дочерними контекстами, созданными всеми DispatcherServlet. Напомню, что корневой контекст приложения будет общим и может быть только один. Root WebApplicationContext содержит компоненты, которые видны всем дочерним контекстам, такие как сервисы, репозитории, компоненты инфраструктуры и т.д. После создания корневого контекста приложения он сохраняется в ServletContext как атрибут, имя которого: ```java WebApplicationContext.class.getName() + ".ROOT" ``` Чтобы из контроллера любого дочернего контекста обратиться к корневому контексту приложения, мы можем использовать класс WebApplicationContextUtils, содержащий статические методы: ```java @Autowired ServletContext context; ApplicationContext ac =WebApplicationContextUtils.getWebApplicationContext(context); if(ac == null){ return "root application context is null"; } ``` __ContextLoaderListener vs DispatcherServlet__ 1. ContextLoaderListener создает корневой контекст приложения. 2. Каждый DispatcherServlet создаёт себе один дочерний контекст. 3. Дочерние контексты могут обращаться к бинам, определенным в корневом контексте. 4. Бины в корневом контексте не могут получить доступ к бинам в дочерних контекстах (напрямую). 5. Все контексты добавляются в ServletContext. 6. Мы можем получить доступ к корневому контексту, используя класс WebApplicationContextUtils. ![Image alt](https://github.com/Shell26/Java-Developer/raw/master/img/Spring4.png) ## В чем разница между Filters, Listeners и Interceptors? __Filter__ Это интерфейс из пакета javax.servlet, имплементации которого выполняют задачи фильтрации либо по пути запроса к ресурсу (сервлету, либо по статическому контенту), либо по пути ответа от ресурса, либо в обоих направлениях. Фильтры выполняют фильтрацию в методе doFilter. Каждый фильтр имеет доступ к объекту FilterConfig, из которого он может получить параметры инициализации, и ссылку на ServletContext, который он может использовать, например, для загрузки ресурсов, необходимых для задач фильтрации. Фильтры настраиваются в дескрипторе развертывания веб-приложения. В веб-приложении мы можем написать несколько фильтров, которые вместе называются цепочкой фильтров. Веб-сервер решает, какой фильтр вызывать первым, в соответствии с порядком регистрации фильтров. Когда вызывается метод doFilter(ServletRequest request, ServletResponse response, FilterChain chain) первого фильтра, веб-сервер создает объект FilterChain, представляющий цепочку фильтров, и передаёт её в метод. ![Image alt](https://github.com/Shell26/Java-Developer/raw/master/img/Spring5.png) __Interceptor__ Это интерфейс из пакета org.aopalliance.intercept, предназначенный для аспектноориентированного программирования. В Spring, когда запрос отправляется в Controller, перед тем как он в него попадёт, он может пройти через перехватчики Interceptor (0 или более). Это одна из реализаций АОП в Spring. Вы можете использовать Interceptor для выполнения таких задач, как запись в Log, добавление или обновление конфигурации перед тем, как запрос обработается Controller-ом. Стек перехватчиков: он предназначен для связывания перехватчиков в цепочку в определенном порядке. При доступе к перехваченному методу или полю перехватчик в цепочке перехватчиков вызывается в том порядке, в котором он был определен. ![Image alt](https://github.com/Shell26/Java-Developer/raw/master/img/Spring6.png) Мы можем использовать Interceptor-ы для выполнения логики до попадания в контроллер, после обработки в контроллере, а также после формирования представления. Также можем запретить выполнение метода контроллера. Мы можем указать любое количество перехватчиков. Перехватчики работают с HandlerMapping и поэтому должны реализовывать интерфейс HandlerInterceptor или наследоваться от готового класса HandlerInterceptorAdapter. В случае реализации HandlerInterceptor нам нужно переопределить 3 метода, а в случае HandlerInterceptor, только необходимые нам: - public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) - вызывается после того, как HandlerMapping определил соответствующий контроллер, но до того, как HandlerAdapter вызовет метод контроллера. С помощью этого метода каждый перехватчик может решить, прервать цепочку выполнения или направить запрос на испольнение дальше по цепочке перехватчиков до метода контроллера. Если этот метод возвращает true, то запрос отправляется следующему перехватчику или в контроллер. Если метод возвращает false, то исполнение запроса прекращается, обычно отправляя ошибку HTTP или записывая собственный ответ в response. - public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) - отработает после контроллера, но перед формированием представления. Мы можем использовать этот метод для добавления дополнительных атрибутов в ModelAndView или для определения времени, затрачиваемого методом-обработчиком на обработку запроса клиента. Вы можете добавить больше объектов модели в представление, но вы не можете изменить HttpServletResponse, так как он уже зафиксирован. - public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) - отработает после формирования представления. Вызывается только в том случае, если метод preHandle этого перехватчика успешно завершен и вернул true! ![Image alt](https://github.com/Shell26/Java-Developer/raw/master/img/Spring7.png) Следует знать, что HandlerInterceptor связан с бином DefaultAnnotationHandlerMapping, который отвечает за применение перехватчиков к любому классу, помеченному аннотацией @Controller. Чтобы добавить наши перехватчики в конфигурацию Spring, нам нужно переопределить метод addInterceptors () внутри класса, который реализует WebMvcConfigurer: ```java @Override public void addInterceptors(InterceptorRegistry registry) { // LogInterceptor applies to all URLs. registry.addInterceptor(new LogInterceptor()); // This interceptor applies to URL /admin/oldLogin. // Using OldURLInterceptor to redirect to new URL. registry.addInterceptor(new OldLoginInterceptor()) .addPathPatterns("/admin/oldLogin"); // This interceptor applies to URLs like /admin/* // Exclude /admin/oldLogin registry.addInterceptor(new AdminInterceptor()) .addPathPatterns("/admin/*")// .excludePathPatterns("/admin/oldLogin"); } ``` __Filter vs. Interceptor__ - Перехватчик основан на механизме Reflection, а фильтр основан на обратном вызове функции. - Фильтр зависит от контейнера сервлета, тогда как перехватчик не зависит от него. - Перехватчики могут работать только с запросами к контроллерам, в то время как фильтры могут работать почти со всеми запросами (например, js, .css и т.д.). - Перехватчики в отличии от фильтров могут обращаться к объектам в контейнере Spring, что даёт им более изощренный функционал. Порядок работы: 1. Фильтры до; 2. Перехватчики до; 3. Метод контроллера; 4. Перехватчики после; 5. Фильтры после. HandlerInterceptor в основном похож на Servlet Filter, но в отличие от последнего он просто позволяет настраивать предварительную обработку с возможностью запретить выполнение самого обработчика и настраивать постобработку. Согласно документации Spring, фильтры более мощные, например, они позволяют обмениваться объектами запроса и ответа, которые передаются по цепочке. Это означает, что фильтры работают больше в области запроса/ответа, в то время как HandlerInterceptors являются бинами и могут обращаться к другим компонентам в приложении. Обратите внимание, что фильтр настраивается в web.xml, а HandlerInterceptor в контексте приложения. __Java Listener__ Listener (Слушатель) - это класс, который реализует интерфейс javax.servlet.ServletContextListener. Он инициализируется только один раз при запуске вебприложения и уничтожается при остановке веб-приложения. Слушатель сидит и ждет, когда произойдет указанное событие, затем «перехватывает» событие и запускает собственное событие. Например, мы хотим инициализировать пул соединений с базой данных до запуска веб-приложения. ServletContextListener - это то, что нам нужно, он будет запускать наш код до запуска веб-приложения. Все ServletContextListeners уведомляются об инициализации контекста до инициализации любых фильтров или сервлетов в веб-приложении. Все ServletContextListeners уведомляются об уничтожении контекста после того, как все сервлеты и фильтры уничтожены. Чтобы создать свой Listener нам достаточно создать класс, имплементирующий интерфейс ServletContextListener и поставить над ним аннотацию @WebListener: ```java @WebListener public class MyAppServletContextListener implements ServletContextListener{ //Run this before web application is started @Override public void contextInitialized(ServletContextEvent arg0) { System.out.println("ServletContextListener started"); } @Override public void contextDestroyed(ServletContextEvent arg0) { System.out.println("ServletContextListener destroyed"); } } ``` ## Связывание форм @ModelAttribute - связывает параметр метода или возвращаемое значение метода с именованным атрибутом модели, а затем возвращает его view веб-представлению. __Когда аннатоцаия используется над методом__, она указывает, что целью этого метода является добавление одного или нескольких атрибутов в модель. При этом Spring-MVC всегда будет сначала вызывать этот метод, прежде чем вызывать какие-либо методы обработчика запросов. То есть, методы @ModelAttribute вызываются до того, как вызываются методы контроллера, аннотированные @RequestMapping. ```java @ModelAttribute public void addAttributes(Model model) { model.addAttribute("msg", "Welcome to the Netherlands!"); } ``` Также важно, чтобы соответствующий класс был помечен как @ControllerAdvice. Таким образом, Вы можете добавить в модель значения, которые будут определены как глобальные. Это фактически означает, что для каждого запроса существует значение по умолчанию, для каждого метода в части ответа. __Когда аннотация ставится в параметрах метода__, она указывает, что аргумент должен быть извлечен из модели. Если такой аргумент отсутствует, его следует сначала создать, а затем добавить в модель, а после того, как он появится в модели, поля аргументов должны быть заполнены из всех параметров запроса, имеющих соответствующие имена. ```java @RequestMapping(value = "/addEmployee", method = RequestMethod.POST) public String submit(@ModelAttribute("employee") Employee employee) { // Code that uses the employee object return "employeeView"; } ``` Атрибут модели сотрудника заполняется данными из формы, отправленной в конечную точку addEmployee. Spring MVC делает это за кулисами перед вызовом метода submit. Таким образом, он связывает данные формы с Bean. Контроллер с аннотацией @RequestMapping может иметь пользовательские аргументы класса с аннотацией @ModelAttribute. Это то, что обычно называют привязкой данных в Spring-MVC, общий механизм, который избавляет вас от необходимости анализировать каждое поле формы по отдельности. ## Исключения в Spring MVC В Spring MVC интерфейс HandlerExceptionResolver (из пакета org.springframework.web.servlet) предназначен для работы с непредвиденными исключениями, возникающими во время выполнения обработчиков. По умолчанию DispatcherServlet регистрирует класс DefaultHandlerExceptionResolver (из пакета org.springframework.web.servlet.mvc.support). Этот распознаватель обрабатывает определенные стандартные исключения Spring MVC, устанавливая специальный код состояния ответа. Можно также реализовать собственный обработчик исключений, аннотировав метод контроллера с помощью аннотации @ExceptionHandler и передав ей в качестве атрибута тип исключения. В общем случае обработку исключений можно описать таким образом: + @ExceptionHandler - указать методы для обработки исключения в классе контроллере. Принимает в себя имя класса обрабатываемого исключения (можно несколько). + @ControllerAdvice - для глобальной обработки ошибок в приложении Spring MVC. Ставится над классом-контроллером, отлавливает все исключения с методов. Он также имеет полный контроль над телом ответа и кодом состояния. + HandlerExceptionResolver implementation – позволяет задать глобального обработчика исключений. Реализацию этого интерфейса можно использовать для создания собственных глобальных обработчиков исключений в приложении. ## Локализация в приложениях Spring MVC Spring MVC предоставляет очень простую и удобную возможность локализации приложения. Для этого необходимо сделать следующее: + Создать файл resource bundle, в котором будут заданы различные варианты локализированной информации. + Определить messageSource в конфигурации Spring используя классы ResourceBundleMessageSource или ResourceBundleMessageSource. + Определить localceResolver класса CookieLocaleResolver для включения возможности переключения локали. + С помощью элемента spring:message DispatcherServlet будет определять в каком месте необходимо подставлять локализированное сообщение в ответе. ## Spring Interceptor Перехватчики в Spring (Spring Interceptor) являются аналогом Servlet Filter и позволяют перехватывать запросы клиента и обрабатывать их. Перехватить запрос клиента можно в трех местах: preHandle, postHandle и afterCompletion. + preHandle — метод используется для обработки запросов, которые еще не были переданы в метода обработчик контроллера. Должен вернуть true для передачи следующему перехватчику или в handler method. False укажет на обработку запроса самим обработчиком и отсутствию необходимости передавать его дальше. Метод имеет возможность выкидывать исключения и пересылать ошибки к представлению. + postHandle — вызывается после handler method, но до обработки DispatcherServlet для передачи представлению. Может использоваться для добавления параметров в объект ModelAndView. + afterCompletion — вызывается после отрисовки представления. Для создания обработчика необходимо расширить абстрактный класс HandlerInterceptorAdapter или реализовать интерфейс HandlerInterceptor. Так же нужно указать перехватчики в конфигурационном файле Spring. [к оглавлению](#spring) ## CommandLineRunner и ApplicationRunner Эти интрефейсы используются для запуска логики при запуске приложения, после создания экземпляра контекста приложения Spring. ApplicationRunner.run() и CommandLineRunner.run() выполнятся сразу после создания applicationcontext и до запуска приложения. Оба они обеспечивают одинаковую функциональность, и единственное различие между CommandLineRunner и ApplicationRunner состоит в том, что CommandLineRunner.run() принимает String array[], тогда как ApplicationRunner.run() принимает ApplicationArguments в качестве аргумента. ```java @Component public class CommandLineAppStartupRunner implements CommandLineRunner { private static final Logger LOG = LoggerFactory.getLogger(CommandLineAppStartupRunner.class); public static int counter; @Override public void run(String...args) throws Exception { LOG.info("Increment counter"); counter++; } } ``` Можно запускать несколько CommandLineRunner одновременно, например чтобы распаралелить сложную логику. Управлять их порядком через @Order. Каждый Runner может иметь свои собственные зависимости ## Реактивное программирование Реактивное программирование — это программирование в многопоточной среде. Реактивный подход повышает уровень абстракции вашего кода и вы можете сконцентрироваться на взаимосвязи событий, которые определяют бизнес-логику, вместо того, чтобы постоянно поддерживать код с большим количеством деталей реализации. Код в реактивном программировании, вероятно, будет короче. Поток — это последовательность, состоящая из постоянных событий, отсортированных по времени. В нем может быть три типа сообщений: значения (данные некоторого типа), ошибки и сигнал о завершении работы. Рассмотрим то, что сигнал о завершении имеет место для экземпляра объекта во время нажатия кнопки закрытия. Мы получаем эти cгенерированные события асинхронно, всегда. Согласно идеологии реактивного программирования существуют три вида функций: те, которые должны выполняться, когда некоторые конкретные данные будут отправлены, функции обработки ошибок и другие функции с сигналами о завершении работы программы. Иногда последнее два пункта можно опустить и сосредоточится на определении функций для обработки значений. Слушать(listening) поток означает подписаться(subscribing) на него. То есть функции, которые мы определили это наблюдатели(observers). А поток является субъектом который наблюдают. Критерии реактивного приложения: __Responsive__. Разрабатываемая система должна отвечать быстро и за определенное заранее заданное время. Кроме того система должна быть достаточно гибкой для самодиагностики и починки. Что это значит на практикте? Традиционно при запросе некоторого сервиса мы идем в базу данных, вынимаем необходимый объем информации и отдаем ее пользователю. Здесь все хорошо, если наша система достаточно быстрая и база данных не очень большая. Но что, если время формирования ответа гораздно больше ожидаемого? Кроме того, у пользователя мог пропасть интернет на несколько миллисекунд. Тогда все усилия по выборке данных и формированию ответа пропадают. Вспомните gmail или facebook. Когда у вас плохой интернет, вы не получаете ошибку, а просто ждете результат больше обычного. Кроме того, этот пункт говорит нам о том, что ответы и запросы должны быть упорядочены и последовательны. __Resilient__. Система остается в рабочем состоянии даже, если один из компонентов отказал. Другими словами, компоненты нашей системы должны быть досточно гибкими и изолированными друг от друга. Достигается это путем репликаций. Если, например, одна реплика PostgreSQL отказала, необходимо сделать так, чтобы всегда была доступна другая. Кроме того, наше приложение должно работать во множестве экземпляров. __Elastic__. Система должна занимать оптимальное количество ресурсов в каждый промежуток времени. Если у нас высокая нагрузка, то необходимо увеличить количество экзепляров приложения. В случае малой нагрузки ресурсы свободных машин должны быть очищены. Типичный инструменты реализации данного принципа: Kubernetes. __Message Driven__. Общение между сервисами должно происходить через асинхронные сообщения. Это значит, что каждый элемент системы запрашивает информацию из другого элемента, но не ожидает получение результата сразу же. Вместо этого он продолжает выполняеть свои задачи. Это позволяет увеличить пользу от системных ресурсов и управлять более гибко возникающими ошибками. Обычно такой результат достигается через реактивное программирование. [к оглавлению](#spring) ## Паттерны в Spring Framework Вот некоторые известные паттерны, используемые в Spring Framework: + Chain of Responsibility - это поведенческий паттерн проектирования, который позволяет передавать запросы последовательно по цепочке обработчиков. Каждый последующий обработчик решает, может ли он обработать запрос сам и стоит ли передавать запрос дальше по цепи. Ему Spring Security + Singleton (Одиночка) - Паттерн Singleton гарантирует, что в памяти будет существовать только один экземпляр объекта, который будет предоставлять сервисы. Spring область видимости бина (scope) по умолчанию равна singleton и IoC-контейнер создаёт ровно один экземпляр объекта на Spring IoC-контейнер. Spring-контейнер будет хранить этот единственный экземпляр в кэше синглтон-бинов, и все последующие запросы и ссылки для этого бина получат кэшированный объект. Рекомендуется использовать область видимости singleton для бинов без состояния. Область видимости бина можно определить как singleton или как prototype (создаётся новый экземпляр при каждом запросе бина). + Model View Controller (Модель-Представление-Контроллер) - Преимущество Spring MVC в том, что ваши контроллеры являются POJO, а не сервлетами. Это облегчает тестирование контроллеров. Стоит отметить, что от контроллеров требуется только вернуть логическое имя представления, а выбор представления остаётся за ViewResolver. Это облегчает повторное использование контроллеров при различных вариантах представления. + Front Controller (Контроллер запросов) - Spring предоставляет DispatcherServlet, чтобы гарантировать, что входящий запрос будет отправлен вашим контроллерам.Паттерн Front Controller используется для обеспечения централизованного механизма обработки запросов, так что все запросы обрабатываются одним обработчиком. Этот обработчик может выполнить аутентификацию, авторизацию, регистрацию или отслеживание запроса, а затем передать запрос соответствующему контроллеру. View Helper отделяет статическое содержимое в представлении, такое как JSP, от обработки бизнес-логики. + Dependency injection и Inversion of control (IoC) (Внедрение зависимостей и инверсия управления) - IoC-контейнер в Spring, отвечает за создание объекта, связывание объектов вместе, конфигурирование объектов и обработку всего их жизненного цикла от создания до полного уничтожения. В контейнере Spring используется инъекция зависимостей (Dependency Injection, DI) для управления компонентами приложения. Эти компоненты называются "Spring-бины" (Spring Beans). + Service Locator (Локатор служб) - ServiceLocatorFactoryBean сохраняет информацию обо всех бинах в контексте. Когда клиентский код запрашивает сервис (бин) по имени, он просто находит этот компонент в контексте и возвращает его. Клиентскому коду не нужно писать код, связанный со Spring, чтобы найти бин. Паттерн Service Locator используется, когда мы хотим найти различные сервисы, используя JNDI. Учитывая высокую стоимость поиска сервисов в JNDI, Service Locator использует кеширование. При запросе сервиса первый раз Service Locator ищет его в JNDI и кэширует объект. Дальнейший поиск этого же сервиса через Service Locator выполняется в кэше, что значительно улучшает производительность приложения. + Observer-Observable (Наблюдатель) - Используется в механизме событий ApplicationContext. Определяет зависимость "один-ко-многим" между объектами, чтобы при изменении состояния одного объекта все его подписчики уведомлялись и обновлялись автоматически. + Context Object (Контекстный объект) - Паттерн Context Object, инкапсулирует системные данные в объекте-контексте для совместного использования другими частями приложения без привязки приложения к конкретному протоколу. ApplicationContext является центральным интерфейсом в приложении Spring для предоставления информации о конфигурации приложения. + Proxy (Заместитель) - позволяет подставлять вместо реальных объектов специальные объекты-заменители. Эти объекты перехватывают вызовы к оригинальному объекту, позволяя сделать что-то до или после передачи вызова оригиналу. + Factory (Фабрика) - определяет общий интерфейс для создания объектов в суперклассе, позволяя подклассам изменять тип создаваемых объектов. + Template (Шаблон) - Этот паттерн широко используется для работы с повторяющимся бойлерплейт кодом (таким как, закрытие соединений и т. п.). [к оглавлению](#spring) ## AOP и составные части Аспектно-ориентированное программирование (АОП) — это парадигма программирования, целью которой является повышение модульности за счет разделения междисциплинарных задач. Это достигается путем добавления дополнительного поведения к существующему коду без изменения самого кода. ООП, AOP и Spring - взаимодополняющие технологии, которые позволяют решать сложные проблемы путем разделения функционала на отдельные модули. АОП предоставляет возможность реализации сквозной логики - т.е. логики, которая применяется к множеству частей приложения - в одном месте и обеспечения автоматического применения этой логики по всему приложению. Подход Spring к АОП заключается в создании "динамических прокси" для целевых объектов и "привязывании" объектов к конфигурированному совету для выполнения сквозной логики. Аспект (Aspect) - Это модуль, который имеет набор программных интерфейсов, которые обеспечивают сквозные требования. К примеру, модуль логирования будет вызывать АОП аспект для логирования. В зависимости от требований, приложение может иметь любое количество аспектов. Объединённая точка (Join point) - Это такая точка в приложении, где мы можем подключить аспект. Другими словами, это место, где начинаются определённые действия модуля АОП в Spring. Совет (Advice) - Это фактическое действие, которое должно быть предпринято до и/или после выполнения метода. Это конкретный код, который вызывается во время выполнения программы. + before - Запускает совет перед выполнением метода. + after - Запускает совет после выполнения метода, независимо от результата его работы (кроме случая остановки работы JVM). + after-returning - Запускает совет после выполнения метода, только в случае его успешного выполнения. + after-throwing - Запускает совет после выполнения метода, только в случае, когда этот метод “бросает” исключение. + around - Запускает совет до и после выполнения метода. При этом инпоинты видят только начало и конец метода. Например, если метод выполняет транзакцию и где-то в середине кода try/catch поймал exception, транзакция все равно будет свершена, rollback не произойдет. В этом случае нужно пробрасывать ошибку за пределы метода. Срез точек (Pointcut) - Срезом называется несколько объединённых точек (join points), в котором должен быть выполнен совет. Введение (Introduction) - Это сущность, которая помогает нам добавлять новые атрибуты и/или методы в уже существующие классы. Целевой объект (Target object) - Это объект на который направлены один или несколько аспектов. Плетение (Weaving) - Это процесс связывания аспектов с другими объектами приложения для создания совета. Может быть вызван во время компиляции, загрузки или выполнения приложения. С помощью АОП мы можем прописать, например, что будет выполняться до или после какого-то действия. Прописываем это один раз и этот функционал будет работать везде. Например нам нужно сделать логирование во всех методах @Service, с ООП нам бы пришлось прописывать этот функционал в каждом методе для всех @Service. А с АОП мы можем в конфигах прописать для @Service что будет происходить с каждым вызовом его методов, - в нашем случае писать логи. Элементы АОП такие как аспекты также используются в транзакциях спринга. ## Spring AOP vs ASPECTJ AspectJ де-факто является стандартом реализации АОП. Реализация АОП от Spring имеет некоторые отличия: + Spring AOP немного проще, т.к. нет необходимости следить за процессом связывания. + Spring AOP поддерживает аннотации AspectJ, таким образом мы можем работать в спринг проекте похожим образом с AspectJ проектом.Spring + AOP поддерживает только proxy-based АОП и может использовать только один тип точек соединения - Method Invocation. AspectJ поддерживает все виды точек соединения. + Недостатком Spring AOP является работа только со своими бинами, которые существуют в Spring Context. [к оглавлению](#spring) ## Некоторые частые аннотации Spring + @Autowired - используется для автоматического связывания зависимостей в spring beans. + @Bean - В классах конфигурации Spring, @Bean используется для для непосредственного создания бина. + @Controller - класс фронт контроллера в проекте Spring MVC. + @ConditionalOn* - Создает бин если выполняется условие. Condition - функциональный интерфейс, который содержит метод boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) + @Sheduler - Таймер. Раз в сколько-то секунд обрабатывать. + @Resource - Java аннотация, которой можно внедрить зависимость. + @Requared - применяется к методам-сеттерам и означает, что значение метода должно быть установлено в XML-файле. Если этого не будет сделано, то мы получим BeanInitializationException. + @RequestMapping - используется для мапинга (связывания) с URL для всего класса или для конкретного метода обработчика. + @ResponseBody - позволяет отправлять Object в ответе. Обычно используется для отправки данных формата XML или JSON. + @ResponseEntity - используется для формирования ответа HTTP с пользовательскими параметрами (заголовки, http-код и т.д.). ResponseEntity необходим, только если мы хотим кастомизировать ответ, добавив к нему статус ответа. Во всех остальных случаях будем использовать @ResponseBody. + @PathVariable - задает динамический маппинг значений из URI внутри аргументов метода обработчика, т.е. позволяет вводить в URI переменную пути в качестве параметра + @Qualifier - используется совместно с @Autowired для уточнения данных связывания, когда возможны коллизии (например одинаковых имен\типов). + @Service - указывает что класс осуществляет сервисные функции. + @Scope - указывает scope у spring bean. + @Configuration, @ComponentScan и @Bean - для java based configurations. + AspectJ аннотации для настройки aspects и advices, @Aspect, @Before, @After,@Around, @Pointcut и др. + @PageableDefault - устанавливает значение по умолчанию для параметра разбиения на страницы ## Различия @Component, @Service, @Repository, @Controller Они все служат для обозначения класса как Бин. + @Component - Spring определяет этот класс как кандидата для создания bean. + @Service - класс содержит бизнес-логику и вызывает методы на уровне хранилища. Ничем не отличается от классов с @Component. + @Repository - указывает, что класс выполняет роль хранилища (объект доступа к DAO). При этом отлавливает определенные исключения персистентности и пробрасывает их как одно непроверенное исключение Spring Framework. Для этого Spring оборачивает эти классы в прокси, и в контекст должен быть добавлен класс PersistenceExceptionTranslationPostProcessor + @Controller - указывает, что класс выполняет роль контроллера MVC. Диспетчер сервлетов просматривает такие классы для поиска @RequestMapping. ## Различия @Controller и @RestController @Controller помечает класс как контроллер HTTP запросов. В Spring 4.0 была представлена аннотация @RestController. Применив ее к контроллеру автоматически добавляются аннотации @Controller, а так же @ResponseBody применяется ко всем методам. ## @Qualifier and @Primary Если есть два одинаковых бина (по типу и имени) спринг не знает какой именно использовать и выдаёт exeption. Если над одним из этих бинов установленна @Primary, то его использовать предпочтительнее. Но если нам нужно использовать в работе оба этих бина, можно над каждым поставить @Qualifier и задать имя, для идентификации этих бинов. ## @Profile Используя аннотацию @Profile - мы сопоставляем bean-компонент с этим конкретным профилем; аннотация просто берет имена одного (или нескольких) профилей. Отвечает за то - какие бины буду создаваться, в зависимости от профайла. Фактически реализована с помощью гораздо более гибкой аннотации @Conditional. Рассмотрим базовый сценарий - у нас есть компонент, который должен быть активным только во время разработки, но не должен использоваться в производстве. Мы аннотируем этот компонент с профилем «dev», и он будет присутствовать в контейнере только во время разработки - в производственном процессе dev просто не будет активен. Или можно задать @Profile("postgres") и @Profile("mysql"), а в application.properties указать, бин с каким профилем использовать = spring.profiles.active = mysql По умолчанию, если профиль бина не определен, то он относится к профилю “default”. Spring также предоставляет способ установить профиль по умолчанию, когда другой профиль не активен, используя свойство «spring.profiles.default». [к оглавлению](#spring) ## @LookUp Используется для внедрения prototype bean в singleton bean. __ПРИМЕР__ - Обычно бины в приложении Spring являтся синглтонами, и для внедрения зависимостей мы используем конструктор или сеттер. Но бывает и другая ситуация: имеется бин Car – синглтон (singleton bean), и ему требуется каждый раз новый экземпляр бина Passenger. То есть Car – синглтон, а Passenger – так называемый прототипный бин (prototype bean). Жизненные циклы бинов разные. Бин Car создается контейнером только раз, а бин Passenger создается каждый раз новый – допустим, это происходит каждый раз при вызове какого-то метода бина Car.Вот здесь то и пригодится внедрение бина с помощью Lookup метода. Оно происходит не при инициализации контейнера, а позднее: каждый раз, когда вызывается метод. ```java @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(); } } ``` Суть в том, что вы создаете метод-заглушку в бине Car и помечаете его специальным образом – аннотацией @Lookup. Этот метод должен возвращать бин Passenger, каждый раз новый. Контейнер Spring под капотом создаст подкласс и переопределит этот метод и будет вам выдавать новый экземпляр бина Passenger при каждом вызове аннотированного метода. Даже если в вашей заглушке он возвращает null (а так и надо делать, все равно этот метод будет переопределен). ```java @Component @Scope("prototype") public class Passenger { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } } ``` Теперь при вызове метода drive() мы можем везти каждый раз нового пассажира. Имя его передаётся в аргументе метода drive(), и затем задается сеттером во вновь созданном экземпляре пассажира. [к оглавлению](#spring) ## @Target и @Retention @Retention - указаываем, в какой момент жизни программного кода будет доступна аннотация + SOURCE - аннотация доступна только в исходном коде и сбрасывается во время создания .class файла; + CLASS - аннотация хранится в .class файле, но недоступна во время выполнения программы; + RUNTIME - аннотация хранится в .class файле и доступна во время выполнения программы. @Target - указывается, какой элемент программы будет использоваться аннотацией + PACKAGE - назначением является целый пакет (package); + TYPE - класс, интерфейс, enum или другая аннотация: + METHOD - метод класса, но не конструктор (для конструкторов есть отдельный тип CONSTRUCTOR); + PARAMETER - параметр метода; + CONSTRUCTOR - конструктор; + FIELD - поля-свойства класса; + LOCAL_VARIABLE - локальная переменная (обратите внимание, что аннотация не может быть прочитана во время выполнения программы, то есть, данный тип аннотации может использоваться только на уровне компиляции как, например, аннотация @SuppressWarnings); + ANNOTATION_TYPE - другая аннотация. [к оглавлению](#spring) ## @Resource Java-аннотация @Resource может применяться к классам, полям и методам. Она пытается получить зависимость: сначала по имени, затем по типу, затем по описанию (Qualifier). Имя извлекается из имени аннотируемого сеттера или поля, либо берется из параметра name. При аннотировании классов имя не извлекается из имени класса по умолчанию, поэтому оно должно быть указано явно. Указав данную аннотацию у полей или методов с аргументом name, в контейнере будет произведен поиск компонентов с данным именем, и в контейнере должен быть бин с таким именем: ```java @Resource(name="namedFile") private File defaultFile; ``` Если указать её без аргументов, то Spring Framework поможет найти бин по типу. Если в контейнере несколько бинов-кандидатов на внедрение, то нужно использовать аннотацию @Qualifier: ```java @Resource @Qualifier("defaultFile") private File dependency1; @Resource @Qualifier("namedFile") private File dependency2; ``` __Разница с @Autowired:__ - ищет бин сначала по имени, а потом по типу; - не нужна дополнительная аннотация для указания имени конкретного бина; - @Autowired позволяет отметить место вставки бина как необязательное @Autowired(required = false); - при замене Spring Framework на другой фреймворк, менять аннотацию @Resource не нужно [к оглавлению](#spring) ## @Inject Размещается над полями, методами, и конструкторами с аргументами. @Inject как и @Autowired в первую очередь пытается подключить зависимость по типу, затем по описанию и только потом по имени. Это означает, что даже если имя переменной ссылки на класс отличается от имени компонента, но они одинакового типа, зависимость все равно будет разрешена: ```java @Inject private ArbitraryDependency fieldInjectDependency; //fieldInjectDependency - отличается от имени компонента, настроенного в контексте приложения: @Bean public ArbitraryDependency injectDependency() { ArbitraryDependency injectDependency = new ArbitraryDependency(); return injectDependency; } ``` Разность имён injectDependency и fieldInjectDependency не имеет значения, зависимость будет подобрана по типу ArbitraryDependency. Если в контейнере несколько бинов-кандидатов на внедрение, то нужно использовать аннотацию @Qualifier: ```java @Inject @Qualifier("defaultFile") private ArbitraryDependency defaultDependency; @Inject @Qualifier("namedFile") private ArbitraryDependency namedDependency; //При использовании конкретного имени (Id) бина используем @Named: @Inject @Named("yetAnotherFieldInjectDependency") private ArbitraryDependency yetAnotherFieldInjectDependency ``` ## @Autowired vs @Resource vs @Inject Аннотации для внедрения зависимостей. @Resource (java) пытается получить зависимость: по имени, по типу, затем по описанию. Имя извлекается из имени аннотируемого сеттера или поля, либо берется из параметра name. @Inject (java) или @Autowired (spring) в первую очередь пытается подключить зависимость по типу, затем по описанию и только потом по имени. ## @Conditional Часто бывает полезно включить или отключить весь класс @Configuration, @Component или отдельные методы @Bean в зависимости от каких-либо условий. Аннотация @Conditional указывает, что компонент имеет право на регистрацию в контексте только тогда, когда все условия соответствуют. Может применяться: - над классами прямо или косвенно аннотированными @Component, включая классы @Configuration; - над методами @Bean; - как мета-аннотация при создании наших собственных аннотаций-условий. Условия проверяются непосредственно перед тем, как должно быть зарегистрировано BeanDefinition компонента, и они могут помешать регистрации данного BeanDefinition. Поэтому нельзя допускать, чтобы при проверке условий мы взаимодействовали с бинами (которых еще не существует), с их BeanDefinition-ами можно. Условия мы определяем в специально создаваемых нами классах, которые должны имплементировать функциональный интерфейс Condition с одним единственным методом, возвращающим true или false: ```java boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) ``` Создав свой класс и переопределив в нем метод matches() с нашей логикой, мы должны передать этот класс в аннотацию @Conditional в качестве параметра: ```java @Configuration @Conditional(OurConditionClass.class) class MySQLAutoconfiguration { //... } //Для того, чтобы проверить несколько условий, можно передать в @Conditional несколько классов с условиями: @Bean @Conditional(HibernateCondition.class, OurConditionClass.class) Properties additionalProperties() { //... } ``` Если класс @Configuration помечен как @Conditional, то на все методы @Bean, аннотации @Import и аннотации @ComponentScan, связанные с этим классом, также будут распространяться указанные условия. Для более детальной настройки классов, аннотированных @Configuration, предлагается использовать интерфейс ConfigurationCondition. В одном классе - одно условие. Для создания более сложных условий можно использовать классы AnyNestedCondition, AllNestedConditions и NoneNestedConditions. В Spring Framework имеется множество готовых аннотаций (и связанных с ними склассами-условиями, имплементирующими интерфейс Condition), которые можно применять совместно над одним определением бина: __ConditionalOnBean__ Условие выполняется, в случае если присутствует нужный бин в BeanFactory. __ConditionalOnClass__ Условие выполняется, если нужный класс есть в classpath. __ConditionalOnCloudPlatform__ Условие выполняется, когда активна определенная платформа. __ConditionalOnExpression__ Условие выполняется, когда SpEL выражение вернуло положительное значение. __ConditionalOnJava__ Условие выполняется, когда приложение запущено с определенной версией JVM. __ConditionalOnJndi__ Условие выполняется, только если через JNDI доступен определенный ресурс. __ConditionalOnMissingBean__ Условие выполняется, в случае если нужный бин отсутствует в контейнере. __ConditionalOnMissingClass__ Условие выполняется, если нужный класс отсутствует в classpath. __ConditionalOnNotWebApplication__ Условие выполняется, если контекст приложения не является веб контекстом. __ConditionalOnProperty__ Условие выполняется, если в файле настроек заданы нужные параметры. __ConditionalOnResource__ Условие выполняется, если присутствует нужный ресурс в classpath. __ConditionalOnSingleCandidate__ Условие выполняется, если bean-компонент указанного класса уже содержится в контейнере и он единственный. __ConditionalOnWebApplication__ Условие выполняется, если контекст приложения является веб контекстом. ## Как управлять транзакциями в Spring Spring поддерживает два типа управления транзакциями: + Программное управление транзакциями: Вы должны управлять транзакциями с помощью программирования. Это способ достаточно гибкий, но его сложно поддерживать. Либо через использование TransactionTemplate, либо через реализацию PlatformTransactionManager напрямую. Используется, если нужно работать с небольшим количеством транзакций. + Декларативное управление транзакциями: Вы отделяете управление транзакциями от бизнес-логики. Вы используете только аннотации @Transactional и конфигурацией на основе XML для управления транзакциями. Наиболее предпочтительный способ. Простая реализация PlatformTransactionManager это DataSourceTransactionManager, который на каждую транзакцию в БД будет создавать Connection. ```java DefaultTransactionDefinition definition = new DefaultTransactionDefinition(); //описание транзакции, можно задавать параметры TransactionStatus status = transactionManager.getTransaction(); //статус транзакции try { fooRepository.insertFoo("name"); transactionManager.commit(status); } catch (RuntimeException e) { transactionManager.rollback(status); } ``` ------------------------------------------------------------------------------------------------------------------------- новая инфа ------------------------------------------------------------------------------------------------------------------------- Для включения возможности управления транзакциями первым делом нужно разместить аннотацию @EnableTransactionManagement у класса-конфигурации @Configuration. Аннотация @EnableTransactionManagement означает, что классы, помеченные @Transactional, должны быть обернуты аспектом транзакций. Однако, если мы используем Spring Boot и имеем зависимости spring-data-* или spring-tx, то управление транзакциями будет включено по умолчанию. @EnableTransactionManagement отвечает за регистрацию необходимых компонентов Spring, таких как TransactionInterceptor и советы прокси (proxy advices- набор инструкций, выполняемых на точках среза - Pointcut). Регистрируемые компоненты помещают перехватчик в стек вызовов при вызове методов @Transactional. Spring создает прокси для всех классов, помеченных @Transactional (либо если любой из методов класса помечен этой аннотацией). Прокси-объекты позволяют Spring Framework вводить транзакционную логику до и после вызываемого метода -главным образом для запуска и коммита/отката транзакции. Если мы разместим аннотацию @Transactional над классом @Service, то все его методы станут транзакционными. Так, при вызове, например, метода save() произойдет примерно следующее: 1. Вначале мы имеем: - класс TransactionInterceptor, у которого основной метод invoke(...), внутри которого вызывается метод класса-родителя TransactionAspectSupport:invokeWithinTransaction(...), в рамках которого происходит магия транзакций. - TransactionManager: решает, создавать ли новый EntityManager и/или транзакцию. - EntityManager proxy: EntityManager - это интерфейс, и то, что внедряется в бин в слое DAO на самом деле не является реализацией EntityManager. В это поле внедряется EntityManager proxy, который будет перехватывать обращение к полю EntityManager и делегировать выполнение конкретному EntityManager в рантайме. Обычно EntityManager proxy представлен классом SharedEntityManagerInvocationHandler. 2. Transaction Interceptor В TransactionInterceptor отработает код до работы метода save(), в котором будет определено, выполнить ли метод save() в пределах уже существующей транзакции БД или должна стартовать новая отдельная транзакция. TransactionInterceptor сам не содержит логики по принятию решения, решение начать новую транзакцию, если это нужно, делегируется TransactionManager. Грубо говоря, на данном этапе наш метод будет обёрнут в try-catch и будет добавлена логика до его вызова и после: ```java try { transaction.begin(); // логика до service.save(); // логика после transaction.commit(); } catch(Exception ex) { transaction.rollback(); throw ex; } ``` 3. TransactionManager Менеджер транзакций должен предоставить ответ на два вопроса: - Должен ли создаться новый EntityManager? - Должна ли стартовать новая транзакция БД? TransactionManager принимает решение, основываясь на следующих фактах: - выполняется ли хоть одна транзакция в текущий момент или нет; - атрибута «propagation» у метода, аннотированного @Transactional (для примера, значение REQUIRES_NEW всегда стартует новую транзакцию). Если TransactionManager решил создать новую транзакцию, тогда: - Создается новый EntityManager; - EntityManager «привязывается» к текущему потоку (Thread); - «Получается» соединение из пула соединений БД; - Соединение «привязывается» к текущему потоку. И EntityManager и это соединение привязываются к текущему потоку, используя переменные ThreadLocal. 4. EntityManager proxy Когда метод save() слоя Service делает вызов метода save() слоя DAO, внутри которого вызывается, например, entityManager.persist(), то не происходит вызов метода persist()напрямую у EntityManager, записанного в поле класса DAO. Вместо этого метод вызывает EntityManager proxy, который достает текущий EntityManager для нашего потока, и у него вызывается метод persist(). 5. Отрабатывает DAO-метод save(). 6. TransactionInterceptor Отработает код после работы метода save(), а именно будет принято решение по коммиту/откату транзакции. Кроме того, если мы в рамках одного метода сервиса обращаемся не только к методу save(), а к разным методам Service и DAO, то все они буду работать в рамках одной транзакции, которая оборачивает этот метод сервиса. Вся работа происходит через прокси-объекты разных классов. Представим, что у нас в классе сервиса только один метод с аннотацией @Transactional, а остальные нет. Если мы вызовем метод с @Transactional, из которого вызовем метод без @Transactional, то оба будут отработаны в рамках прокси и будут обернуты в нашу транзакционную логику. Однако, если мы вызовем метод без @Transactional, из которого вызовем метод с @Transactional, то они уже не будут работать в рамках прокси и не будут обернуты в нашу транзакционную логику. ------------------------------------------------------------------------------------------------------------------------- старая инфа ------------------------------------------------------------------------------------------------------------------------- Аннотация сама по себе определяет область действия одной транзакции БД. Транзакция БД происходит внутри области действий persistence context. Persistence контекстом в JPA является EntityManager, который использует внутри класс Session ORM-фреймворка Hibernate (при использовании Hibernate как persistence провайдера). Persistence контекст это объект-синхронайзер, который отслеживает состояния ограниченного набора Java объектов и синхронизирует изменения состояний этих объектов с состоянием соответствующих записей в БД. Один объект Entity Manager не всегда соответствует одной транзакции БД. Один объект Entity Manager может быть использован несколькими транзакциями БД. Самый частый случай такого использования - когда приложение использует шаблон «Open Session in View» для предотвращения исключений «ленивой» инициализации. В этом случае запросы, которые могли быть выполнены одной транзакцией при вызове из слоя сервиса, выполняются в отдельных транзакциях в слое View, но они совершаются через один и тот же Entity Manager. При этом @PersistenceContext не может внедрить entity manager напрямую. Entity Manager это интерфейс, и то что внедряется в бин не является самим по себе entity менеджером, это context aware proxy, который будет делегировать к конкретному entity менеджеру в рантайме. Но прокси persistence контекста, которое имлементирует EntityManager не является достаточным набором компонентов для осуществления декларативного управления транзакциями. На самом деле нужно три компонента: + Прокси Entity менеджера + Аспект транзакций + Менеджер транзакций __Аспект транзакций__ — «around» аспект, который вызывается и до и после выполнения аннотированного бизнес метода. Конкретный класс для имплементации этого аспекта это TransactionInterceptor. Аспект транзакций имеет две главные функции: + В момент «до» аспект определяет выполнить ли выполняемый метод в пределах уже сущестувующей транзакции БД или должна стартовать новая отдельная транзакция. В момент «до» аспект сам не содержит логики по принятию решения, решение начать новую транзакцию, если это нужно, делегируется Transaction менеджеру. + В момент «после» аспект решает что делать с транзакцией, делать коммит, откат или оставить незакрытой. __Transaction менеджер__ Менеджер транзакций должен предоствить ответ на два вопроса: Должен ли создаться новый Entity Manager? Должна ли стартовать новая транзакция БД? Ответы необходимы предоставить в момент когда вызывается логика аспекта транзакций в момент «до». Менеджер транзакций принимает решение, основываясь на следующих фактах: выполняется ли хоть одна транзакция в текущий момент; нет ли атрибута «propagation» у метода, аннотированного @Transactional (для примера, REQUIRES_NEW всегда стартует новую транзакцию). Если менеджер решил создать новую транзакцию, тогда: Создается новый entity менеджер «Привязка» entity менеджера к текущему потоку (Thread) «Взятие» соединения из пула соединений БД «Привязка» соединения к текущему потоку И entity менеджер и это соединение привязываются к текущему потоку, используя переменные ThreadLocal. Они хранятся в потоке, пока выполняется транзакция, и затем передаются менеджеру транзакций для очистки, когда они уже будут не нужны. Любая часть программы, которой нужен текущий entity manager или соединение, может заполучить их из потока. Этим компонентом программы, который делает именно так является Entity Manager Proxy. __EntityManager proxy__ ПКогда бизнес метод делает вызов, например, entityManager.persist(), этот вызов не вызывается напрямую у entity менеджера. Вместо этого бизнес метод вызывает прокси, который достает текущий entity менеджер из потока, в который его положил менеджер транзакций. Как использовать: 1) В файле конфигурации нужно определить менеджер транзакций transactionManager для DataSource. ```java ``` 2) Включить поддержку аннотаций, добавив запись в контекстном xml файле вашего spring-приложения ИЛИ добавьте @EnableTransactionManagement в ваш конфигурационный файл 3) Добавить аннотацию @Transactional в класс (метод класса) или интерфейс (метод интерфейса). У @Transactional есть ряд параметров: + @Transactional (isolation=Isolation.READ_COMMITTED) - уровень изоляции. + @Transactional(timeout=60) - По умолчанию используется таймаут, установленный по умолчанию для базовой транзакционной системы. Сообщает менеджеру tx о продолжительности времени, чтобы дождаться простоя tx, прежде чем принять решение об откате не отвечающих транзакций. + @Transactional(propagation=Propagation.REQUIRED_NEW) - (Если не указано, распространяющееся поведение по умолчанию — REQUIRED.) Когда вызывается метод с @Transactional происходит особая уличная магия: proxy, который создал Spring, создаёт persistence context (или соединение с базой), открывает в нём транзакцию и сохраняет всё это в контексте нити исполнения (натурально, в ThreadLocal). По мере надобности всё сохранённое достаётся и внедряется в бины. Привязка транзакций к нитям (threads) позволяет использовать семантику серверов приложений J2EE, в которой гарантируется, что каждый запрос получает свою собственную нить. Таким образом, если в вашем коде есть несколько параллельных нитей, у вас будет и несколько параллельных транзакций, которые будут взаимодействовать друг с другом согласно уровням изоляции. Но что произойдёт, если один метод с @Transactional вызовет другой метод с @Transactional? В Spring можно задать несколько вариантов поведения, которые называются правилами распространения. __REQUIRES__ - При входе в @Transactional метод будет использована уже существующая транзакция или создана новая транзакция, если никакой ещё нет __REQUIRES_NEW__ - Транзакция всегда создаётся при входе метод с Propagation.REQUIRES_NEW, ранее созданные транзакции приостанавливаются до момента возврата из метода. __NESTED__ — корректно работает только с базами данных, которые умеют savepoints (Postgres в том числе). Savepoints — транзакции внутри транзакций. Savepoint позволяет сохранить какое-либо состояние внутри транзакции и, при необходимости, откатиться к нему, не откатывая всю транзакцию. При входе в метод в уже существующей транзакции создаётся savepoint, который по результатам выполнения метода будет либо сохранён, либо откачен. Все изменения, внесённые методом, подтвердятся только поздее, с подтверждением всей транзакции. Если текущей транзакции не существует, будет создана новая. __MANDATORY__ - обратный по отношению к REQUIRES_NEW: всегда используется существующая транзакция и кидается исключение, если текущей транзакции нет. __SUPPORTS__ - метод с этим правилом будет использовать текущую транзакцию, если она есть, либо будет исполнятся без транзакции, если её нет. Методы, которые извлекают данные, являются лучшими кандидатами для этой опции. __NOT_SUPPORTED__ - При входе в метод текущая транзакция, если она есть, будет приостановлена и метод будет выполняться без транзакции. В основном те методы, которые выполняются в транзакции, но выполняют операции с оперативной памятью, являются лучшими кандидатами для этой опции. __NEVER__ - явно запрещает исполнение в контексте транзакции. Если при входе в метод будет существовать транзакция, будет выброшено исключение. Этот вариант в большинстве случаев не используется в проектах. + @Transactional (rollbackFor=Exception.class) - Значение по умолчанию: rollbackFor=RunTimeException.class В Spring все классы API бросают RuntimeException, это означает, что если какой-либо метод не выполняется, контейнер всегда откатывает текущую транзакцию. Проблема заключается только в проверенных исключениях - при них транзакция пройдет в БД даже при ошибке. С этим параметром проверяемые исключения тоже будут откатываться при ошибке + @Transactional (noRollbackFor=IllegalStateException.class) - Указывает, что откат не должен происходить, если целевой метод вызывает это исключение. Если внутри метода с @Transactional есть другой метод с аннотацией @Transactional (вложенная транзакция), то отработает только первая (в которую вложенна). Из-за особенностей создания proxy. Но у аннотации @Transactional можно указать параметры. Куда же ставить @Transactional? Классическое приложение обычно имеет многослойную архитектуру: контроллеры > слой логики > слой доступа к данным > слой ORM Где здесь место для @Transactional? Слой ORM обычно никто не пишет сам и использует какое-либо стандартное решение, в которое аннотации не вставишь. Слой доступа к данным обычно представляет собой набор классов, методы которых реализуют тот или иной запрос. Получается, что если каждый метод аннотировать @Transactional, то, с одной стороны, работать это конечно будет, а с другой стороны теряется смысл транзакций, как логического объединения нескольких запросов в одну единицу работы. Ведь в таком случае у каждого метода, то есть у каждого запроса, будет своя, собственная, транзакция. Слой логики представляется идеальным местом для @Transactional: именно здесь набор запросов к базе оформляется в единую осмысленную операцию в приложении. Зная, что делает ваше приложение, вы можете четко разграничить логические единицы работы в нём и расставить границы транзакций. Слой контроллеров тоже может быть неплохим местом для @Transactional, но у него есть два недостатка, по сравнению со слоем логики. Во первых он взаимодействует с пользователем, напрямую или через сеть, что может делать транзакции длиннее: метод будет ждать отправки данных или реакции пользователя и в этом время продолжать удерживать транзакцию и связанные с ней блокировки. Во вторых это нарушает принцип разделения ответственности: код, который должен быть ответственен за интерфейс с внешним миром, становится ответственен и за часть управления логикой приложения. И последнее — никогда не аннотируйте интерфейсы. Аннотации не наследуются и поэтому, в зависимости от настроек Spring, вы можете внезапно оказаться фактически без своих @Transactional [к оглавлению](#spring) ## Как Spring работает с DAO Spring DAO предоставляет возможность работы с доступом к данным с помощью технологий вроде JDBC, Hibernate в удобном виде. Существуют специальные классы: JdbcDaoSupport, HibernateDaoSupport, JdoDaoSupport, JpaDaoSupport. Класс HibernateDaoSupport является подходящим суперклассом для Hibernate DAO. Он содержит методы для получения сессии или фабрики сессий. Самый популярный метод - getHibernateTemplate(), который возвращает HibernateTemplate. Этот темплейт оборачивает checked-исключения Hibernate в runtime-исключения, позволяя вашим DAO оставаться независимыми от исключений Hibernate. [к оглавлению](#spring) ## Model vs ModelMap vs ModelAndView Интерфейс Model инкапсулирует (объединяет) данные приложения. ModelMap реализует этот интерфейс, с возможностью передавать коллекцию значений. Затем он обрабатывает эти значения, как если бы они были внутри Map. Следует отметить, что в Model и ModelMap мы можем хранить только данные. Мы помещаем данные и возвращаем имя представления. С другой стороны, с помощью ModelAndView мы возвращаем сам объект. Мы устанавливаем всю необходимую информацию, такую как данные и имя представления, в объекте, который мы возвращаем. [к оглавлению](#spring) ## В чем разница между model.put() и model.addAttribute()? Метод addAttribute отделяет нас от работы с базовой структурой hashmap. По сути addAttribute это обертка над put, где делается дополнительная проверка на null. Метод addAttribute в отличии от put возвращает modelmap. [к оглавлению](#spring) ## PreparedStatementCreator PreparedStatement - нужен для защиты от SQL-инъекций в запросах, а PreparedStatementCreator - для создания возврата PreparedStatement из connection. При этом он автоматически обрабатывает все исключения (кроме SQLExeption). [к оглавлению](#spring) ## SOAP vs REST SOAP – это целое семейство протоколов и стандартов, для обмена структурированными сообщениями. Это более тяжеловесный и сложный вариант с точки зрения машинной обработки. Поэтому REST работает быстрее. REST - это не протокол и не стандарт, а архитектурный стиль. У этого стиля есть свои принципы: __Give every “thing” an ID__; __Link things together__ - Например, в страницу (представление) о Mercedes C218 хорошо бы добавить ссылку на страницу конкретно о двигателе данной модели, чтобы желающие могли сразу туда перейти, а не тратить время на поиск этой самой страницы; __Use standard methods__ - Имеется в виду, экономьте свои силы и деньги заказчика, используйте стандартные методы HTTP, например GET http://www.example.com/cars/00345 для получения данных вместо определения собственных методов вроде getCar?id=00345; __Resources can have multiple representations__ - Одни и те же данные можно вернуть в XML или JSON для программной обработки или обернутыми в красивый дизайн для просмотра человеком; __Communicate statelessly__ - Да, RESTful сервис должен быть как идеальный суд – его не должно интересовать ни прошлое подсудимого (клиента), ни будущее – он просто выносит приговор (отвечает на запрос). Термин RESTful (веб-)сервис всего лишь означает сервис, реализованный с использованием принципов REST. При этом SOAP и REST – не конкуренты. Они представляют разные весовые категории и вряд ли найдется задача, для которой будет сложно сказать, какой подход рациональнее использовать – SOAP или REST. [к оглавлению](#spring) ## Spring Data Spring Data — дополнительный удобный механизм для взаимодействия с сущностями базы данных, организации их в репозитории, извлечение данных, изменение, в каких то случаях для этого будет достаточно объявить интерфейс и метод в нем, без имплементации. + CrudRepository - обеспечивает функции CRUD + PagingAndSortingRepository - предоставляет методы для разбивки на страницы и сортировки записей + JpaRepository - предоставляет связанные с JPA методы. При этом JpaRepository содержит полный API CrudRepository и PagingAndSortingRepository Основное понятие в Spring Data — это репозиторий. Это несколько интерфейсов которые используют JPA Entity для взаимодействия с ней. Так например интерфейс ( public interface CrudRepository extends Repository ) обеспечивает основные операции по поиску, сохранения, удалению данных (CRUD операции). Т.е. если того перечня что предоставляет интерфейс достаточно для взаимодействия с сущностью, то можно прямо расширить базовый интерфейс для своей сущности, дополнить его своими методами запросов и выполнять операции. Понятно что этого перечня, скорее всего не хватит для взаимодействия с сущностью, и тут можно расширить свой интерфейс дополнительными методами запросов. Запросы к сущности можно строить прямо из имени метода. Для этого используется механизм префиксов find…By, read…By, query…By, count…By, и get…By, далее от префикса метода начинает разбор остальной части. Вводное предложение может содержать дополнительные выражения, например, Distinct. Далее первый By действует как разделитель, чтобы указать начало фактических критериев. Можно определить условия для свойств сущностей и объединить их с помощью And и Or. Если нужен специфичный метод или его реализация, которую нельзя описать через имя метода, то это можно сделать через некоторый Customized интерфейс ( CustomizedEmployees) и сделать реализацию вычисления. А можно пойти другим путем, через указание запроса (HQL или SQL), как вычислить данную функцию. Отметив запрос аннотацией @Query. Нативный запрос можно написать так: ```java public interface RoleRepository extends JpaRepository{ Optional findRoleByRoleName(String name); @Modifying @Transactional @Query(value = "INSERT INTO user_roles (user_id, role_id) VALUE (:user_id, :role_id)", nativeQuery = true) void insertRoles(@Param("user_id) Long user_id, @Param("role_id") Long role_id); //можно использовать с EntityGraph, обычным, не NamedEntityGraph @EntityGraph(value = "customer.products") List findAll(@Nullable Specification specification) ``` ## Конфигурация Spring Data Поскольку мы используем JPA, нам нужно определить свойства для подключения к базе данных в файле persistence.xml, а не в hibernate.cfg.xml. Создайте новый каталог с именем META-INF в исходной папке проекта, чтобы поместить в него файл persistence.xml. Затем прописать в вайле свойства для подключения к базе, например: ```java ``` Для работы с Spring Data JPA нам надо создать два beans-компонента: EntityManagerFactory и JpaTransactionManager. Поэтому создадим другой конфигурационный класс JpaConfig: ```java @Configuration @EnableJpaRepositories(basePackages = {"net.codejava.customer"}) @EnableTransactionManagement public class JpaConfig { @Bean public LocalEntityManagerFactoryBean entityManagerFactory() { LocalEntityManagerFactoryBean factoryBean = new LocalEntityManagerFactoryBean(); factoryBean.setPersistenceUnitName("SalesDB"); return factoryBean; } @Bean public JpaTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) { JpaTransactionManager transactionManager = new JpaTransactionManager(); transactionManager.setEntityManagerFactory(entityManagerFactory); return transactionManager; } } ``` @EnableJpaRepositories: сообщает Spring Data JPA, что нужно искать классы репозитория в указанном пакете (net.codejava) для внедрения соответсвующего кода во время выполнения. @EnableTransactionManagement: сообщает Spring Data JPA, чтобы тот генерировал код для управления транзакциями во время выполнения. В этом классе первый метод создаёт экземпляр EntityManagerFactory для управления Persistence Unit нашей SalesDB (это имя указано выше в persistence.xml). Последний метод создаёт экземпляр JpaTransactionManager для EntityManagerFactory, созданный методом ранее. Это минимальная необходимая конфигурация для использования Spring Data JPA. ## Spring Security Spring Security предоставляет широкие возможности для защиты приложения. Кроме стандартных настроек для аутентификации, авторизации и распределения ролей и маппинга доступных страниц, ссылок и т.п., предоставляет защиту от различных вариантов атак Spring Security - это список фильтров в виде класса FilterChainProxy, интегрированного в контейнер сервлетов, и в котором есть поле List. Каждый фильтр реализует какой-то механизм безопасности. Важна последовательность фильтров в цепочке. ![Image alt](https://github.com/Shell26/Java-Developer/raw/master/img/Spring8.png) Когда мы добавляем аннотацию @EnableWebSecurity добавляется DelegatingFilterProxy, его задача заключается в том, чтобы вызвать цепочку фильтров (FilterChainProxy) из Spring Security. В Java-based конфигурации цепочка фильтров создается неявно. Если мы хотим настроить свою цепочку фильтров, мы можем сделать это, создав класс, конфигурирующий наше Spring Security приложение, и имплементировав интерфейс WebSecurityConfigurerAdapter. В данном классе, мы можем переопределить метод: ```java @Override protected void configure(HttpSecurity http) throws Exception { http .csrf().disable() .authorizeRequests(); } ``` Именно этот метод конфигурирует цепочку фильтров Spring Security и логика, указанная в этом методе, настроит цепочку фильтров. __Основные классы и интерфейсы__ __SecurityContext__ - интерфейс, отражающий контекст безопасности для текущего потока. Является контейнером для объекта типа Authentication. (Аналог - ApplicationContext, в котором лежат бины). По умолчанию на каждый поток создается один SecurityContext. SecurityContext-ы хранятся в SecurityContextHolder. Имеет только два метода: getAuthentication() и setAuthentication(Authentication authentication). __SecurityContextHolder__ - это место, где Spring Security хранит информацию о том, кто аутентифицирован. Класс, хранящий в ThreadLocal SecurityContext-ы для каждого потока, и содержащий статические методы для работы с SecurityContext-ами, а через них с текущим объектом Authentication, привязанным к нашему веб-запросу. ![Image alt](https://github.com/Shell26/Java-Developer/raw/master/img/Spring9.png) __Authentication__ - объект, отражающий информацию о текущем пользователе и его привилегиях. Вся работа Spring Security будет заключаться в том, что различные фильтры и обработчики будут брать и класть объект Authentication для каждого посетителя. Кстати объект Authentication можно достать в Spring MVC контроллере командой SecurityContextHolder.getContext().getAuthentication(). Authentication имеет реализацию по умолчанию - класс UsernamePasswordAuthenticationToken, предназначенный для хранения логина, пароля и коллекции Authorities. __Principal__ - интерфейс из пакета java.security, отражающий учетную запись пользователя. В терминах логин-пароль это логин. В интерфейсе Authentication есть метод getPrincipal(), возвращающий Object. При аутентификации с использованием имени пользователя/пароля Principal реализуется объектом типа UserDetails. __Credentials__ - любой Object; то, что подтверждает учетную запись пользователя, как правило пароль (отпечатки пальцев, пин - всё это Credentials, а владелец отпечатков и пина - Principal). __GrantedAuthority__ - полномочия, предоставленные пользователю, например, роли или уровни доступа. __UserDetails__ - интерфейс, представляющий учетную запись пользователя. Как правило модель нашего пользователя должна имплементировать его. Она просто хранит пользовательскую информацию в виде логина, пароля и флагов isAccountNonExpired, isAccountNonLocked, isCredentialsNonExpired, isEnabled, а также коллекции прав (ролей)пользователя. Данная информация позже инкапсулируется в объекты Authentication. __UserDetailsService__ - интерфейс объекта, реализующего загрузку пользовательских данных из хранилища. Созданный нами объект с этим интерфейсом должен обращаться к БД и получать оттуда юзеров. используется чтобы создать UserDetails объект путем реализации единственного метода этого интерфейса ```java UserDetails loadUserByUsername(String username) throws UsernameNotFoundException; ``` __AuthenticationManager__ - основной стратегический интерфейс для аутентификации. Имеет только один метод, который срабатывает, когда пользователь пытается аутентифицироваться в системе: ```java public interface AuthenticationManager { Authentication authenticate(Authentication authentication) throws AuthenticationException; } ``` AuthenticationManager может сделать одну из 3 вещей в своем методе authenticate(): 1. вернуть Authentication (с authenticated=true), если предполагается, что вход осуществляет корректный пользователь. 2. бросить AuthenticationException, если предполагается, что вход осуществляет некорректный пользователь. 3. вернуть null, если принять решение не представляется возможным. Наиболее часто используемая реализация AuthenticationManager - родной класс ProviderManager, который содержит поле private Listproviders со списком AuthenticationProvider-ов и итерирует запрос аутентификации по этому списку AuthenticationProvider-ов. Идея такого разделения - поддержка различных механизмов аутентификации на сайтах. AuthenticationProvider - интерфейс объекта, выполняющего аутентификацию. Имеет массу готовых реализаций. Также можем задать свой тип аутентификации. Как правило в небольших проектах одна логика аутентификации - по логину и паролю. В проектах побольше логик может быть несколько: Google-аутентификация и т.д., и для каждой из них создается свой объект AuthenticationProvider. AuthenticationProvider немного похож на AuthenticationManager, но у него есть дополнительный метод, позволяющий вызывающей стороне спрашивать, поддерживает ли он переданный ему объект Authentication, возможно этот AuthenticationProvider может поддерживать только аутентификацию по логину и паролю, но не поддерживать Googleаутентификацию: ```java boolean supports(java.lang.Class authentication) ``` PasswordEncoder - интерфейс для шифрования/расшифровывания паролей. Одна из популярных реализаций - BCryptPasswordEncoder. В случае, если нам необходимо добавить логику при успешной/неудачной аутентификации, мы можем создать класс и имплементировать интерфейсы AuthenticationSuccessHandler и AuthenticationFailureHandler соответственно, переопределив их методы. Как это работает с формой логина и UserDetailsService: - Пользователь вводит в форму и отправляет логин и пароль. - UsernamePasswordAuthenticationFilter создает объект Authentication - UsernamePasswordAuthenticationToken, где в качестве Principal - логин, а в качестве Credentials - пароль. - Затем UsernamePasswordAuthenticationToken передаёт объект Authentication с логином и паролем AuthenticationManager-у. - AuthenticationManager в виде конкретного класса ProviderManager внутри своего списка объектов AuthenticationProvider, имеющих разные логики аутентификации, пытается аутентифицировать посетителя, вызывая его метод authenticate(). У каждого AuthenticationProvider-а: 1 Метод authenticate() принимает в качестве аргумента незаполненный объект Authentication, например только с логином и паролем, полученными в форме логина на сайте. Затем с помощью UserDetailsService метод идёт в БД и ищет такого пользователя. 2 Если такой пользователь есть в БД, AuthenticationProvider получает его из базы в виде объекта UserDetails. Объект Authentication заполняется данными из UserDetails - в него включаются Authorities, а в Principal записывается сам объект UserDetails, содержащий пользователя. 3 Затем этот метод возвращает заполненный объект Authentication (прошли аутентификацию). Вызывается AuthenticationSuccessHandler. 4 Если логин либо пароль неверные, то выбрасывается исключение. Вызывается AuthenticationFailureHandler. - Затем этот объект Authentication передается в AccessDecisionManager и получаем решение на получение доступа к запрашиваемой странице (проходим авторизацию). Аннотации: + @EnableGlobalMethodSecurity - включает глобальный метод безопасности. + @EnableWebMvcSecurity - "включает" Spring Security. Не будет работать, если наш класс не наследует WebSecurityConfigurerAdapter + @Secured используется для указания списка ролей в методе + @PreAuthorize и @PostAuthorize обеспечивают контроль доступа на основе выражений. @PreAuthorize проверяет данное выражение перед входом в метод, тогда как аннотация @PostAuthorize проверяет его после выполнения метода и может изменить результат. + @PreFilter для фильтрации аргумента коллекции перед выполнением метода [к оглавлению](#spring) ## Spring Boot По сути, Spring Boot это просто набор классов конфигурации, которые создают нужные бины в контексте. Точно так же их можно создать руками, просто Boot это автоматизирует. При этом помогая решить проблему конфликтов разных версий компонентов. Чтобы ускорить процесс управления зависимостями, Spring Boot неявно упаковывает необходимые сторонние зависимости для каждого типа приложения на основе Spring и предоставляет их разработчику посредством так называемых starter-пакетов (spring-boot-starter-web, spring-boot-starter-data-jpa и т.д.) Starter-пакеты представляют собой набор удобных дескрипторов зависимостей, которые можно включить в свое приложение. Это позволит получить универсальное решение для всех, связанных со Spring технологий, избавляя программиста от лишнего поиска примеров кода и загрузки из них требуемых дескрипторов зависимостей. Например, если вы хотите начать использовать Spring Data JPA для доступа к базе данных, просто включите в свой проект зависимость spring-boot-starter-data-jpa и все будет готово (вам не придется искать совместимые драйверы баз данных и библиотеки Hibernate) Например, если вы добавите Spring-boot-starter-web, Spring Boot автоматически сконфигурирует такие зарегистрированные бины, как DispatcherServlet, ResourceHandlers, MessageSource. Если вы используете spring-boot-starter-jdbc, Spring Boot автоматически регистрирует бины DataSource, EntityManagerFactory, TransactionManager и считывает информацию для подключения к базе данных из файла application.properties В основе "магии" Spring Boot нет ничего магического, он использует совершенно базовые понятия из Spring Framework. В кратком виде процесс можно описать так: + Аннотация @SpringBootApplication включает сканирование компонентов и авто-конфигурацию через аннотацию @EnableAutoConfiguration + @EnableAutoConfiguration импортирует класс EnableAutoConfigurationImportSelector + EnableAutoConfigurationImportSelector загружает список конфигураций из файла META-INF/spring.factories + Каждая конфигурация пытается сконфигурить различные аспекты приложения (web, JPA, AMQP etc), регистрируя нужные бины и используя различные условия (наличие / отсутствие бина, настройки, класса и т.п.) + Созданный в итоге AnnotationConfigEmbeddedWebApplicationContext ищет в том же DI контейнере фабрику для запуска embedded servlet container + Servlet container запускается, приложение готово к работе! Важное понятие Spring Boot это автоконфигурация. По сути, это просто набор конфигурационных классов, которые создают и регистрируют определенные бины в приложении. По большому счету, даже сам Embedded Servlet Container — это просто еще один бин, который можно сконфигурировать! Пара важных моментов, которые важно знать об автоконфигурации: + Включается аннотацией @EnableAutoConfiguration + Работает в последнюю очередь, после регистрации пользовательских бинов + Принимает решения о конфигурации на основании доступных в classpath классов, свойств в application.properties и т.п. + Можно включать и выключать разные аспекты автоконфигурации, и применять ее частично (например, только MySQL + JPA, но не веб) + Всегда отдает приоритет пользовательским бинам. Если ваш код уже зарегистрировал бин DataSource — автоконфигурация не будет его перекрывать Логика при регистрации бинов управляется набором @ConditionalOn* аннотаций. Можно указать, чтобы бин создавался при наличии класса в classpath (@ConditionalOnClass), наличии существующего бина (@ConditionalOnBean), отсуствии бина (@ConditionalOnMissingBean) и т.п. Отключить ненужные автоконфигурации можно при помощи свойств exclude и excludeName аннотаций @EnableAutoConfiguration, @ImportAutoConfiguration и @SpringBootApplication. Или в property задать SpringAutoconfiguration exclude и передать имена классов. Можно отказаться от использования механизма автоконфигурации, вместо этого указывая необходимые автоконфигурации вручную. Для этого надо избавиться от аннотаций @SpringBootApplication и @EnableAutoConfiguration в коде вашего проекта, а для указания нужных конфигурационных классов использовать аннотации @SpringBootConfiguration и @ImportAutoConfiguration. Однако стоит помнить, что используемые автоконфигурации всё ещё могут содержать неиспользуемые компоненты. __Как происходит автоконфигурация в Spring Boot:__ 1. Отмечаем main класс аннотацией @SpringBootApplication (аннотация инкапсулирует в себе:@SpringBootConfiguration, @ComponentScan, @EnableAutoConfiguration), таким образом наличие @SpringBootApplication включает сканирование компонентов, автоконфигурацию и показывает разным компонентам Spring (например, интеграционным тестам), что это Spring Boot приложение. ```java @SpringBootApplication public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } } ``` 2. @EnableAutoConfiguration импортирует класс EnableAutoConfigurationImportSelector. Этот класс не объявляет бины сам, а использует так называемые фабрики. 3. Класс EnableAutoConfigurationImportSelector смотрит в файл META-INF/spring.factories и загружает оттуда список значений, которые являются именами классов (авто)конфигураций, которые Spring Boot импортирует. Т.е. аннотация @EnableAutoConfiguration просто импортирует ВСЕ (более 150) перечисленные в spring.factories конфигурации, чтобы предоставить нужные бины в контекст приложения. 4. Каждая из этих конфигураций пытается сконфигурировать различные аспекты приложения(web, JPA, AMQP и т.д.), регистрируя нужные бины. Логика при регистрации бинов управляется набором @ConditionalOn* аннотаций. Можно указать, чтобы бин создавался при наличии класса в classpath (@ConditionalOnClass), наличии существующего бина (@ConditionalOnBean), отсуствии бина (@ConditionalOnMissingBean) и т.п. Таким образом наличие конфигурации не значит, что бин будет создан, и в большинстве случаев конфигурация ничего делать и создавать не будет. 5. Созданный в итоге AnnotationConfigEmbeddedWebApplicationContext ищет в том же DI контейнере фабрику для запуска embedded servlet container. 6. Servlet container запускается, приложение готово к работе! [к оглавлению](#spring) ## Starter packs Чтобы ускорить процесс управления зависимостями, Spring Boot неявно упаковывает необходимые сторонние зависимости для каждого типа приложения на основе Spring и предоставляет их разработчику посредством так называемых starter-пакетов. Starter-пакеты представляют собой набор удобных дескрипторов зависимостей, которые можно включить в свое приложение. Делаем свой Starter-пакет: + Создаем AutoConfiguration-класс, который Spring Boot находит при запуске приложения и использует для автоматического создания и конфигурирования бинов. ```java @Configuration //указываем, что наш класс является конфигурацией (@Configuration) @ConditionalOnClass({SocialConfigurerAdapter.class, VKontakteConnectionFactory.class}) //означает, что бины будут создаваться при наличии в classpath SocialConfigurerAdapter и VKontakteConnectionFactory. Таким образом, без нужных для нашего стартера зависимостей бины создаваться не будут. @ConditionalOnProperty(prefix= "ru.shadam.social-vkontakte", name = { "client-id", "client-secret"}) //означает, что бины будут создаваться только при наличии property ru.shadam.social-vkontakte.client-id и ru.shadam.social-vkontakte.client-secret. @AutoConfigureBefore(SocialWebAutoConfiguration.class) @AutoConfigureAfter(WebMvcAutoConfiguration.class) //означает, что наш бин будет инициализироваться после WebMvc и до SocialWeb. Это нужно, чтобы к моменту инициализации SocialWeb наши бины уже были зарегистрированы. public class VKontakteAutoConfiguration { } ``` + Расширяем SocialConfigurationAdapter, который нужен для того чтобы зарегистрировать нашу ConnectionFactory. Для этого переопределяем метод addConnectionFactories(ConnectionFactoryConfigurer, Environment) + Создание файла, позволяющего SpringBoot найти наш AutoConfiguration класс. Для этого существует специальный файл spring.factories, который нужно поместить в META-INF папку получающегося jar-файла. В этом файле нам надо указать наш AutoConfiguration-класс. + Подключить получившийся jar-файл к Spring Boot проекту и задать в конфигурации пути на класс, который создали до этого. https://www.youtube.com/watch?v=nGfeSo52_8A&t=1735s (с 30мин) [к оглавлению](#spring) ## Как внедрить java.util.Properties в Spring Bean Используя SpEL ```java @Value("${maxReadResults}") private int maxReadResults; ``` Или определить propertyConfigure bean в XML. [к оглавлению](#spring) ## Что нового в Spring 5 + Используется JDK 8+ (Optional, CompletableFuture, Time API, java.util.function, default methods) + Поддержка Java 9 (Automatic-Module-Name in 5.0, module-info in 6.0+, ASM 6) + Поддержка HTTP/2 (TLS, Push), NIO/NIO.2, Kotlin + Поддержка Kotlin + Реактивность (Web on Reactive Stack) + Null-safety аннотации(@Nullable), новая документация + Совместимость с Java EE 8 (Servlet 4.0, Bean Validation 2.0, JPA 2.2, JSON Binding API 1.0) + Поддержка JUnit 5 + Testing Improvements (conditional and concurrent) + Удалена поддержка: Portlet, Velocity, JasperReports, XMLBeans, JDO, Guava [к оглавлению](#spring) ## RestTemplate и JDBCTemplate Класс RestTemplate является центральным инструментом для выполнения клиентских HTTP-операций в Spring. Он предоставляет несколько утилитных методов для создания HTTP-запросов и обработки ответов. JdbcTemplate - базовый класс, который управляет обработкой всех событий и связями с БД посредством sql запросов. При этом все пишется программистом, не автоматизированно. [к оглавлению](#spring) ## Socket Класс для двунаправленное соединением между клиентом и сервером. Например пользователь чатится с другим пользователем, сокет обрабатывает эти сообщения. Отвечает за создание соединения и пересылку данных. [к оглавлению](#spring) Полный курс по Spring. 1. # 1. Intro 2. lesson 1. Введение 3. Модули Spring (out of the box) 4. Удобство и простота использования 5. Микросервисная архитектура 6. Support & Community 7. Что нужно знать для изучения курса Spring 8. lesson 2. Установка программного обеспечения 9. Установка Java 17 10. Установка IntelliJ IDEA Ultimate Edition 11. Установка PostgreSQL 12. Установка Docker 13. Создание нового проекта 14. lesson 3. Inversion of Control. Dependency Injection 15. Object Dependencies 16. Object Dependencies в коде 17. Inversion of Control & Dependency Injection 18. Inversion of Control & Dependency Injection в коде 19. 3 способа внедрения зависимостей в объекте 20. lesson 4. IoC Container 21. Spring IoC Container 22. Bean 23. Bean Definition 24. POJO 25. Основные интерфейсы IoC Container 26. 3 способа создания Bean Definitions 27. # 2. XML-based Configuration 28. lesson 5. XML-based Configuration 29. BeanFactory и ApplicationContext интерфейсы 30. ClassPathXmlApplicationContext 31. XML config 32. Идентификаторы (id) бинов как ключи в IoC Container 33. Алиасы бинов (alias) 34. lesson 6. Constructor Injection 35. Внедрение примитивных типов данных 36. Внедрение коллекций list/set 37. Внедрение ассоциативного массива map 38. Поле genericArgumentValues в BeanDefinition 39. Поле indexedArgumentValues в BeanDefinition 40. Указание атрибута type в параметрах конструктора 41. Указание атрибута name в параметрах конструктора 42. lesson 7. Factory Method Injection 43. Внедрение других бинов через ref* 44. Создание новое бина CompanyRepository 45. Внедрение зависимостей через factory method 46. Атрибут factory-bean (паттерн ServiceLocator) 47. lesson 8. Property Injection 48. Использование set* методов в ConnectionPool 49. Поле propertyValues в BeanDefinition 50. Упрощенный жизненный цикл бинов - Bean Lifecycle 51. Плюсы и минусы Constructor и Property Injections 52. Циклические зависимости через Property Injection 53. lesson 9. Bean Scopes 54. Common Bean Scopes 55. Custom Bean Scopes 56. Web Bean Scopes 57. Prototype Bean Scope 58. lesson 10. Lifecycle Callbacks 59. Измененный Bean Lifecycle 60. Initialization callbacks 61. Destruction callbacks 62. lesson 11. Injection from Properties Files 63. Зачем использовать properties files 64. Создание файла application.properties 65. PropertySourcesPlaceholderConfigurer bean 66. Expression Language (EL) 67. Spring Expression Language (SpEL) 68. SpEL документация 69. System properties 70. lesson 12. BeanFactoryPostProcessor (BFPP) 71. Интерфейс BeanFactoryPostProcessor 72. Как работает PropertySourcesPlaceholderConfigurer 73. Измененный Bean Lifecycle 74. Метод isAssignableFrom 75. lesson 13. Custom BeanFactoryPostProcessor 76. Создание собственных BeanFactoryPostProcessor 77. Интерфейс Ordered 78. Интерфейс PriorityOrdered 79. # 3. Annotation-based Configuration 80. lesson 14. Annotation-based Configuration 81. Подключение зависимости jakarta annotation api 82. Аннотации @PostConstruct и @PreDestroy 83. Класс CommonAnnotationBeanPostProcessor 84. context:annotation-config xml element 85. lesson 15. BeanPostProcessor (BPP) 86. Интерфейс BeanPostProcessor 87. Bean Lifecycle (final version) 88. Интерфейс Aware 89. Класс ApplicationContextAwareProcessor 90. lesson 16. Custom BeanPostProcessor. Часть 1 91. Создание своей аннотации @InjectBean 92. Создание InjectBeanPostProcessor 93. Утилитный класс ReflectionUtils 94. Тестирование InjectBeanPostProcessor 95. lesson 17. Custom BeanPostProcessor. Часть 2 96. Создание аннотации @Transaction 97. Создание CrudRepository 98. Создание TransactionBeanPostProcessor 99. Тестирование TransactionBeanPostProcessor 100. Корректируем TransactionBeanPostProcessor 101. Создание AuditingBeanPostProcessor 102. lesson 18. @Autowired & @Value 103. Аннотация @Autowired 104. Аннотация @Resource 105. Решение конлифкта бинов. @Qualifier 106. Collection injection 107. Properties injection. @Value 108. lesson 19. Classpath Scanning 109. context:component-scan. Аннотации @Component 110. Замена бинов из xml на @Component 111. lesson 20. Bean Definition Readers 112. Component Scan classes 113. Bean Definition Readers 114. Класс ComponentScanBeanDefinitionParser 115. Класс AnnotatedBeanDefinitionReader 116. lesson 21. Type Filters 117. Атрибут annotation-config 118. Атрибут name-generator 119. Атрибут resource-pattern 120. Атрибут scoped-proxy 121. Атрибут scope-resolver 122. Атрибут use-default-filters 123. 5 type filters 124. Custom filters 125. lesson 22. @Scope 126. Атрибут scope-resolver 127. Класс AnnotationScopeMetadataResolver 128. Аннотация @Scope 129. lesson 23. JSR 250, JSR 330 130. Аббревиатура JSR 131. JSR 250 132. JSR 330 133. Класс Jsr330ScopeMetadataResolver 134. # 4. Java-based Configuration 135. lesson 24. Java-based Configuration 136. Класс ConfigurationClassBeanDefinitionReader 137. Создание ApplicationConfiguration. @Configuration 138. Аннотация @PropertySource 139. Аннотация @ComponentScan 140. Класс AnnotationConfigApplicationContext 141. lesson 25. @Import & @ImportResource 142. Класс AnnotationConfigApplicationContext 143. Аннотация @ImportResource 144. Аннотация @Import 145. lesson 26. @Bean. Часть 1 146. Аннотация @Bean 147. Тестирование Java конфигурации 148. Свойства аннотации @Bean 149. Аннотация @Scope с @Bean 150. Внедрение зависимостей с @Bean 151. Конфликт имен @Bean и @Component 152. lesson 27. @Bean. Часть 2 153. 3-ий вариант внедрения зависимостей в @Bean 154. Cglib proxy в @Configuration 155. Свойство proxyBeanMethods в @Configuration 156. @Bean создаются через паттерн Service Locator 157. lesson 28. Profiles 158. Environment Bean 159. Аннотация @Profile 160. Активация profiles через properties 161. Активация profiles через ApplicationContext 162. # 5. Event Listeners 163. lesson 29. Event Listeners. Часть 1 164. Шаблон проектирования Listener 165. Создание события (Event) 166. Создание слушателя событий (Listener). @EventListener 167. Реализация логики для отправки события 168. lesson 30. Event Listeners. Часть 2 169. Bean ApplicationEventPublisher 170. Тестирование слушателей событий 171. Listeners order 172. Listeners conditions 173. # 6. Spring Boot 174. lesson 31. Spring Boot. Введение 175. Spring modules 176. Spring Data Configuration 177. Modules Auto Configuration 178. Conditions 179. Spring Boot Starters 180. Dependency Management 181. How to build Spring Boot Application 182. lesson 32. @Conditional 183. Аннотация @Conditional 184. Класс Condition 185. Custom JpaCondition 186. Тестирование JpaCondition 187. Аннотация @Profile 188. Другие @Condition аннотации 189. lesson 33. Spring Boot. Настройка проекта 190. Spring Boot Gradle Plugin 191. Spring Dependency Management Plugin 192. spring-boot-starter 193. Run Spring Boot Application 194. Autogenerated Spring Boot Project 195. Maven spring-boot-starter-parent pom 196. lesson 34. @SpringBootApplication 197. Структура Spring Boot приложения 198. Что делает метод SpringApplication.run 199. Аннотация @SpringBootApplication 200. Аннотация @SpringBootConfiguration 201. Аннотация @ComponentScan 202. Аннотация @PropertySource 203. Аннотация @EnableAutoConfiguration 204. lesson 35. Lombok 205. Подключение Lombok 206. Gradle Lombok Plugin 207. IntelliJ IDEA Lombok Plugin 208. Аннотации Lombok 209. Файл lombok.config 210. lesson 36. Properties 211. Файл spring.properties 212. Externalized Configuration 213. Profile-specific properties 214. Spring program arguments & VM options 215. Property Placeholders & Default values 216. spring.config.location 217. lesson 37. Yaml format 218. YAML - Yet Another Markup Language 219. Класс YamlPropertiesFactoryBean 220. Приоритет properties vs yaml 221. Переписывание application.properties на yaml 222. lesson 38. @ConfigurationProperties 223. Класс JpaProperties 224. Класс DatabaseProperties 225. Аннотация @ConfigurationProperties 226. Аннотация @ConfigurationPropertiesScan 227. Immutable DatabaseProperties 228. DatabaseProperties as record 229. Property key names 230. # 7. Logging Starter 231. lesson 39. Logging Starter 232. Application as a Black Box 233. Logging libraries 234. Log Levels 235. spring-boot-starter-logging dependency 236. Аннотация @Slf4j 237. Delombok annotations 238. Формат логов по умолчанию 239. logging.* properties 240. lesson 40. Logback Configuration 241. Logback default xml configs 242. File Output 243. Custom log configuration 244. # 8. Test Starter 245. lesson 41. Test Starter 246. Подключение spring-boot-starter-test 247. Транзитивные зависимости spring-boot-starter-test 248. Зависимость spring-test 249. Зависимость spring-boot-test 250. Зависимость spring-boot-test-autoconfigure 251. Пример написания Unit тестов 252. Java Gradle Plugin tasks relationship 253. lesson 42. Integration Testing. Part 1 254. Основные цели Spring Integration Testing 255. Жизненный цикл тестов 256. JUnit 5 Extension Model 257. TestContext Framework 258. SpringExtension source code 259. lesson 43. Integration Testing. Part 2 260. Создание CompanyServiceIT 261. SpringExtension via @ExtendWith 262. Аннотация @ContextConfiguration 263. Аннотация @TestPropertySource 264. Класс ApplicationContextInitializer 265. Аннотация @SpringBootTest 266. Написание первого интеграционного теста 267. Класс DependencyInjectionTestExecutionListener 268. lesson 44. Integration Testing. Part 3 269. Аннотация @ActiveProfiles 270. Custom Test Annotations 271. Аннотация @TestConstructor 272. Замена @TestConstructor на spring.properties 273. lesson 45. Context Caching 274. Создание нескольких ApplicationContext в тестах 275. Аннотации @MockBean и @SpyBean 276. Класс MockitoTestExecutionListener 277. Аннотация @TestConfiguration 278. Аннотация @DirtiesContext 279. # 9. Data JPA Starter 280. lesson 46. Data JPA Starter. Введение 281. Чего не хватало в Hibernate 282. Установка PostgreSQL 283. Установка Docker 284. Postgres Docker Image 285. Подключение к postgres из IntelliJ IDEA 286. lesson 47. Data JPA Starter. Подключение 287. Подключение spring-boot-starter-data-jpa 288. Зависимости spring-boot-starter-data-jpa 289. Класс HibernateJpaAutoConfiguration 290. Настройка spring.datasource и spring.jpa properties 291. Тестирование приложения 292. lesson 48. Hibernate Entities 293. UML диаграмма выполненных sql скриптов 294. Создание сущности Company 295. Создание коллекции locales (ElementCollection) 296. Создание сущности User 297. Создание сущности Payment 298. Создание сущности Chat 299. Создание сущности UserChat 300. Проверка маппинга сущностей через hbm2ddl.auto 301. Аннотация @EntityScan 302. # 10. Data JPA Transactions 303. lesson 49. @Transactional. TestContext 304. Общая структура работы с TransactionManager 305. Создание CompanyRepository IT 306. Аннотации @Transactional из Jakarta EE и Spring 307. Класс TransactionalTestExecutionListener 308. Аннотации @Commit и @Rollback 309. lesson 50. TransactionAutoConfiguration 310. Класс TransactionAutoConfiguration 311. Как происходит обработка транзакций в proxy 312. Аннотация @Transactional и Cglib proxy 313. Как работает Cglib proxy с TransactionManager 314. Как подключить механизм транзакций внутри объекта (не proxy) 315. Механизм транзакций между несколькими Cglib proxy 316. lesson 51. @Transactional Settings 317. Свойства @Transactional. transactionManager 318. Transaction propagation 319. Transaction propagation резюме 320. Transaction isolation 321. Transaction timeout 322. ReadOnly transaction 323. Transaction rollbackFor & rollbackForClassName 324. Transaction noRollbackFor & noRollbackForClassName 325. lesson 52. Manual Transactions 326. Свойства объекта TransactionTemplate 327. Функционал TransactionTemplate 328. Обработка checked exceptions 329. Взаимодействие TransactionTemplate с другими Proxy 330. Вынесение @Transactional в @IT 331. # 11. Data JPA Repositories 332. lesson 53. Repository 333. Интерфейс Repository 334. Написание теста на удаление Company 335. Класс JpaRepositoryAutoConfiguration 336. lesson 54. RepositoryQuery 337. Создание Proxy на классы Repository 338. Класс QueryExecutorMethodInterceptor 339. Класс RepositoryQuery 340. Наследники Repository 341. lesson 55. PartTreeJpaQuery 342. Класс PartTreeJpaQuery 343. Примеры написания запросов 344. Тестирование запросов 345. Весь список ключевых слов PartTreeJpaQuery 346. lesson 56. NamedQuery 347. Недостатки PartTreeJpaQuery 348. Класс NamedQuery 349. Аннотация @NamedQuery 350. Тестирование NamedQuery 351. Аннотация @Param 352. lesson 57. @Query 353. StoredProcedureJpaQuery 354. Аннотация @Query 355. Демонстрация работы @Query 356. Усовершенствованный оператор LIKE 357. Native Query 358. lesson 58. @Modifying 359. Запрос на обновление через @Query 360. Аннотация @Modifying 361. Hibernate PersistenceContext 362. Свойства clearAutomatically и flushAutomatically 363. clearAutomatically и LazyInitializationException 364. lesson 59. Special parameters 365. Top & First 366. TopN & FirstN 367. Класс Sort 368. Класс Pageable 369. lesson 60. Page & Slice 370. Spring классы Streamable, Slice, Page 371. Демонстрация работы Slice объекта 372. Почему Slice объекта недостаточно 373. Демонстрация работы Page объекта 374. lesson 61. @EntityGraph 375. Аннотация @EntityGraph 376. Именованные графы @NamedEntityGraph 377. Свойство attributePaths в @EntityGraph 378. Конфликт Pageable при получении EAGER связей 379. lesson 62. @Lock & @QueryHints 380. Аннотация @Lock 381. Демонстрация пессимистических блокировок 382. Аннотация @QueryHints 383. lesson 63. Projection 384. Class-based Projections 385. Generic Class-based Projections 386. Interface-based Projections 387. SpEL in Projections 388. lesson 64. Custom Repository Implementation 389. Запрос фильтрации через Custom Implementation 390. Criteria API для запроса фильтрации 391. Аннотация @EnableJpaRepository 392. Тестирование запроса фильтрации 393. lesson 65. JPA Auditing 394. Создание AuditingEntity 395. Аннотация @EnableJpaAuditing 396. Тестирование @CreatedDate и @LastModifiedDate 397. Аннотации @CreatedBy и @LastModifiedBy 398. Создание AuditorAware Bean 399. Тестирование @CreatedBy и @LastModifiedBy 400. lesson 66. Hibernate Envers 401. Подключение Hibernate Envers 402. Создание сущности Revision 403. Аннотация @Audited 404. Аннотация @EnableEnversRepositories 405. #Тестирование Hibernate Envers 406. Класс RevisionRepository 407. lesson 67. Querydsl 408. Подключение Querydsl 409. Создание QPredicates 410. Замена Criteria API на Querydsl 411. Тестирование Querydsl 412. Класс QuerydslPredicateExecutor 413. # 12. JDBC Starter 414. lesson 68. JDBC Starter 415. Зависимость spring-boot-starter-jdbc 416. JdbcTemplateAutoConfiguration 417. Функционал класса JdbcTemplate 418. Практика JdbcTemplate 419. Подключение логов для JdbcTemplate 420. lesson 69. Batch size & Fetch size 421. Batch запросы 422. Batch запрос через JdbcTemplate 423. Тестирование Batch запроса через JdbcTemplate 424. Batch запрос через NamedParameterJdbcTemplate 425. Установка batch_size в Hibernate 426. Fetch size 427. # 13. Databases in tests 428. lesson 70. In-Memory databases. H2 429. Два варианта поднятия тестовой базы данных 430. Подключение H2 database 431. Аннотация @Sql 432. lesson 71. Testcontainers 433. testcontainers lib 434. Подключение testcontainers 435. Создание IntegrationTestBase 436. Тестирование testcontainers 437. Тестовые данные (ids) 438. # 14. Database Migrations 439. lesson 72. Liquibase. Теория 440. Устройство migration frameworks 441. Стуктура Liquibase changelog 442. Changelog master file 443. lesson 73. Liquibase. Практика 444. Подключение зависимости liquibase-core 445. Класс LiquibaseAutoConfiguration 446. Создание master changelog 447. liquibase formatted sql 448. Тестирование Liquibase 449. Добавление нового changelog (envers tables) 450. md5sum 451. Использование Liquibase в тестах 452. # 15. Web Starter 453. lesson 74. Web Starter. Введение 454. MVC и классические web-приложения 455. web-приложение на Spring Boot 456. Embedded Tomcat 457. Настройка spring-web приложения 458. Класс WebMvcAutoConfiguration 459. lesson 75. Dispatcher Servlet 460. Жизненный цикл сервлетов 461. Псевдокод метода service в DispatcherServlet 462. Исходный код класса DispatcherServlet 463. lesson 76. @Controller 464. Подключение зависимостей и настройка view resolver 465. Создание контроллера. @Controller 466. lesson 77. @RequestMapping 467. Основные составляющие HTTP запроса и HTTP ответа 468. Основные составляющие URL 469. Аннотации @RequestMapping 470. lesson 78. Parameters, Headers, Cookies 471. Parameters. @RequestParam annotation 472. Headers. @RequestHeader annotation 473. Cookies. @CookieValue annotation 474. Method params naming 475. DispatcherServlet sources 476. @PathVariable annotation 477. lesson 79. Model 478. Attributes 479. Добавление Request атрибутов в Model 480. Добавление Session атрибутов в Model 481. DispatcherServlet sources 482. lesson 80. @ModelAttribute 483. Упрощение работы с объектом ModelAndView 484. Динамическое создание атрибутов 485. Аннотация @ModelAttribute 486. HTML Form. LoginController 487. lesson 81. Forward, Include, Redirect 488. 3 вида перенаправления запросов 489. forward in Spring 490. redirect in Spring 491. lesson 82. CRUD. API Design 492. API design best practices 493. CRUD. Method findAll 494. CRUD. Method findById 495. CRUD. Method create 496. CRUD. Method update 497. CRUD. Method delete 498. lesson 83. CRUD. Service Layer 499. UserService. Method findAll 500. UserService. Method findById 501. UserService. Method create 502. @Transactional annotation 503. UserService. Method update 504. UserService. Method delete 505. Test UserService functionality 506. Tips. Method delete 507. lesson 84. Spring MVC Testing 508. Аннотация @AutoConfigureMockMvc 509. Test findAll method 510. Transactions. spring.jpa.open-in-view property 511. Test create method 512. Problem with sending dates in params 513. lesson 85. Type Converters 514. 1. spring.mvc.format properties 515. 2. Аннотация @DateTimeFormat 516. 3. Интерфейс WebMvcConfigurer 517. # 16. Thymeleaf 518. lesson 86. Thymeleaf Starter. Введение 519. View Resolvers 520. Thymeleaf Template Engine Intro 521. Настройка Thymeleaf в проекте 522. Использование Thymeleaf 523. lesson 87. CRUD. View Layer. Часть 1 524. Создание users.html для метода findAll 525. Создание user.html для метода findById 526. Добавление кнопки для метода delete 527. lesson 88. CRUD. View Layer. Часть 2 528. Создание registration endpoint 529. Создание registration.html registration 530. redirect с сохранением введенных параметров 531. lesson 89. Filter Query 532. Add UserFilter - Controller & Service layers 533. Add UserFilter - users.html 534. lesson 90. Pagination. Best practices 535. HTTP endpoints best practices 536. 2 options of pagination implementation 537. offset-based pagination 538. PageableArgumentResolver 539. Building PageResponse 540. # 17. Validation Starter 541. lesson 91. Validation Starter. Введение 542. Подключение validation starter 543. Validation annotations 544. How to use annotations in practice 545. @Valid & @Validated 546. BindingResult object 547. Show validation errors on the page 548. lesson 92. Custom validator 549. Main parts in JSR 303 annotations 550. Custom annotation @UserInfo 551. Configuration properties validation 552. Validation groups 553. lesson 93. @ControllerAdvice & @ExceptionHandler 554. @ExceptionHandler annotation 555. @ControllerAdvice annotation 556. Класс ResponseEntityExceptionHandler 557. # 18. REST 558. lesson 94. REST. Введение 559. Проблемы Controller API 560. REST API 561. REST API Usages 562. lesson 95. REST. Практика 563. @ResponseBody & findAll method 564. findById method 565. @RequestBody & create method 566. update method 567. delete method 568. @RestController 569. @RestControllerAdvice 570. lesson 96. Swagger. API docs 571. Rest clients 572. Подключение springdoc 573. Сгенерированная документация для Rest Controllers 574. Swagger ui 575. Swagger annotations 576. lesson 97. Upload image 577. Добавление новой колонки image в таблице users 578. Создание ImageService 579. upload images from html pages. MultipartFile 580. lesson 98. Get image 581. Реализация функционала на уровне service 582. Отображение картинки на html странице 583. Реализация функционала на уровне rest controller 584. Отображение отсутствующей картинки 585. Класс ResponseEntity 586. # 19. Security Starter 587. lesson 99. Security Starter. Введение 588. Понятия Аутентификация и Авторизация 589. Servlet Filters mechanism 590. Spring Servlet Filters mechanism 591. Подключение Spring Security Starter 592. lesson 100. Authentication Architecture 593. Spring Security Model 594. Spring Security Authentication Logic 595. Debug Security filters (default behaviour) 596. lesson 101. DaoAuthenticationProvider 597. DaoAuthenticationProvider source code 598. Add column password into users table 599. Update entity & enum 600. Implement UserDetailsService 601. Тестирование функциональности 602. lesson 102. Form Login 603. Default login page source code 604. Custom login page 605. Customise SecurityFilterChain 606. Тестирование функицонала 607. Class UsernamePasswordAuthenticationFilter 608. lesson 103. HTTP Basic Authentication 609. HTTP Basic Authentication principle 610. HTTP Basic encoder & decoder 611. Customise SecurityFilterChain to support HTTP Basic 612. BasicAuthenticationFilter source code 613. lesson 104. PasswordEncoder 614. Зачем шифровать пароли 615. List of password encoders 616. Implement password encode/decode in the app 617. lesson 105. Logout 618. LogoutFilter source code 619. Customise logout in SecurityFilterChain 620. Add button Logout on pages 621. lesson 106. Authorization Architecture 622. AuthorizationFilter source code and logic 623. AuthorizationFilter implementations 624. Customise authorizeHttpRequests in SecurityFilterChain 625. lesson 107. Method Security 626. @PreAuthorize annotation 627. @PostAuthorize annotation 628. @EnableMethodSecurity annotation 629. @Secured annotation 630. Service layer authentication 631. @PreFilter & @PostFilter annotations 632. lesson 108. Access to authenticated user 633. Get current user via SecurityContextHolder 634. @CurrentSecutiryContext annotation 635. @AuthenticationPrincipal annotation 636. Thymeleaf and Spring Security integration 637. lesson 109. CSRF Filter 638. Cross-Site Request Forgery 639. How to solve CSRF problem 640. Synchronizer Token Pattern 641. When to use CSRF protection 642. CsrfFilter source code 643. How to work with CSRF token 644. Class CsrfRequestDataValueProcessor 645. lesson 110. Security Testing 646. Исправление существующих тестов 647. spring-security-test dependency 648. 1. Manually define a user in tests 649. 2. @WithMockUser annotation 650. 3. SecurityMockMvcRequestPostProcessor 651. lesson 111. OAuth 2.0. Теория 652. Текущий Authentication функционал в приложении 653. Что такое OAuth 2 654. Как внедрить OAuth 2 в приложении 655. OAuth 2 flow types 656. OAuth 2 Authorization Code Flow 657. OAuth 2 Implicit Flow 658. OpenID Connect (OIDC) 659. lesson 112. OAuth 2.0. Практика 660. Create a new project in GCP 661. Configure OAuth 2 in the project 662. Configure Login Page 663. lesson 113. OAuth 2.0. Authentication Principle 664. Add UserInfoEndpoint config in SecurityFilterChain 665. Create oidcUserService 666. lesson 114. JWT. JSON Web Token 667. How to extract info from JWT 668. JWT header 669. JWT payload 670. JWT signature 671. Code Book 672. lesson 115. Swagger Authorization 673. 3 options to pass authorization in Swagger 674. springdoc properties to support OAuth 2 675. @SecurityScheme configuration 676. # 20. i18n & l10n 677. lesson 116. i18n. MessageSource 678. spring.messages properties 679. IntelliJ IDEA UTF-8 settings 680. Creating MessageRestController 681. lesson 117. i18n. Thymeleaf 682. Login page i18n 683. How to change the language 684. LocalChangeInterceptor bean 685. LocaleResolver bean 686. # 21. AOP Starter 687. lesson 118. AOP Starter. Введение 688. Усложнение кода второстепенной логикой 689. Crosscutting concerns 690. AOP terminology 691. AOP approaches 692. lesson 119. AOP. Pointcut 693. spring-boot-starter-aop dependency 694. AspectJ annotations 695. @Pointcut 696. @within 697. within 698. this & target 699. @annotation 700. args 701. @args 702. bean 703. execution 704. lesson 120. AOP. @Before Advice 705. @Before annotation 706. CglibAopProxy 707. Proxy interceptors 708. Spring AOP diagram 709. AopAutoConfiguration 710. lesson 121. AOP. JoinPoint. Params 711. JoinPoint object 712. Get access to proxy data from advice method params 713. argNames 714. lesson 122. AOP. @After Advices 715. All types of advice 716. @AfterReturning annotation 717. @AfterThrowing annotation 718. @After annotation 719. lesson 123. AOP. @Around Advice 720. TransactionInterceptor 721. @Around annotation 722. lesson 124. AOP. Best Practices 723. 1. Combine different Pointcut types 724. 2. Move common Pointcuts to separate Aspect 725. 3. Don t use @Around advice everywhere 726. 4. Separate Pointcuts by business logic 727. Aspects order 728. # 22. Заключение 729. lesson 125. Custom Spring Boot Starter 730. Create a new Gradle module 731. Define starter properties 732. Create Autoconfiguration 733. File META-INF/spring.factories 734. Move Aspects from the old to the new module 735. How to use newly created starter 736. spring-boot-configuration-processor 737. lesson 126. Заключение. Путь развития 738. Spring Framework Documentation 739. List of all main Spring Boot Starters 740. Java Road Map