Slide 1

Slide 1 text

Микросервисы Через терни в пропасть к звездам

Slide 2

Slide 2 text

Какие архитектурные шаблоны вы знаете?

Slide 3

Slide 3 text

Сегодня мы говорим про распределенные системы

Slide 4

Slide 4 text

Микросервисы!!!

Slide 5

Slide 5 text

Я тебе дам,микросервисы!

Slide 6

Slide 6 text

CORBA

Slide 7

Slide 7 text

CORBA. Как это работало

Slide 8

Slide 8 text

CORBA. Плюсы ● Независимость от конкретного языка или технологии (не считая ORB) ● Простое соблюдение контракта

Slide 9

Slide 9 text

CORBA. Минусы ● Смешение локальных и распределенных географически взаимодействий ведет к непредсказуемым проблемам с производительностью

Slide 10

Slide 10 text

CORBA. Минусы ● Смешение локальных и распределенных географически взаимодействий ведет к непредсказуемым проблемам с производительностью ● Сложная раздутая спецификация с проблемами версий от разных вендоров

Slide 11

Slide 11 text

CORBA. Минусы ● Смешение локальных и распределенных географически взаимодействий ведет к непредсказуемым проблемам с производительностью ● Сложная раздутая спецификация с проблемами версий от разных вендоров ● Специфические протоколы поверх tcp/ip, порты которых часто попадали под блокировки

Slide 12

Slide 12 text

CORBA. Минусы ● Смешение локальных и распределенных географически взаимодействий ведет к непредсказуемым проблемам с производительностью ● Сложная раздутая спецификация с проблемами версий от разных вендоров ● Специфические протоколы поверх tcp/ip, порты которых часто попадали под блокировки

Slide 13

Slide 13 text

Решали проблемы как могли

Slide 14

Slide 14 text

Проблема надежности канал связи ● Отказ от кастомных протоколов и переход на HTTP ● Переход на платформонезависимые языки спецификации сообщений (json, xml)

Slide 15

Slide 15 text

Проблема локальности обращений ● Отказ от слоя абстракции скрывающего процесс получения данных - удаленные вызовы стали явными, разработчики стали следить за количеством удаленных вызовов

Slide 16

Slide 16 text

Проблема сложной спецификации ● CORBA умер, SOAP учел его ошибки ● ...но не до конца, REST был проще и почти закопал SOAP ● ...продолжение следует

Slide 17

Slide 17 text

Родился SOA

Slide 18

Slide 18 text

SOA Service 3 Service 1 Service 2 HTTP JSON XML

Slide 19

Slide 19 text

Распостранение SOA

Slide 20

Slide 20 text

SOA. Плюсы ● Независимость набора технологий, развёртывания и масштабируемости сервисов. ● Удобство параллелизации разработки

Slide 21

Slide 21 text

SOA. Плюсы ● Независимость набора технологий, развёртывания и масштабируемости сервисов. ● Удобство параллелизации разработки ● Стандартный, простой и надёжный канал связи (передача текста по HTTP через порт 80). ● Оптимизированный обмен сообщениями

Slide 22

Slide 22 text

SOA. Плюсы ● Независимость набора технологий, развёртывания и масштабируемости сервисов. ● Удобство параллелизации разработки ● Стандартный, простой и надёжный канал связи (передача текста по HTTP через порт 80). ● Оптимизированный обмен сообщениями ● Стабильная спецификация обмена сообщениями. ● Изолированность контекстов доменов (Domain contexts).

Slide 23

Slide 23 text

SOA. Минусы ● Сложность развертывания ● Сложность обновления ● Сложность мониторинга

Slide 24

Slide 24 text

Наплодили сервисов Поддержка

Slide 25

Slide 25 text

SOA

Slide 26

Slide 26 text

Я знаю другой шаблон

Slide 27

Slide 27 text

Ситуация

Slide 28

Slide 28 text

Много существующих сервисов с разными протоколами

Slide 29

Slide 29 text

Можно конечно по стандартному пути

Slide 30

Slide 30 text

А можно попытаться как-то объединить

Slide 31

Slide 31 text

Шина

Slide 32

Slide 32 text

Шина. Плюсы ● Независимость технологий, развёртывания и масштабирования

Slide 33

Slide 33 text

Шина. Плюсы ● Независимость технологий, развёртывания и масштабирования ● Стандартный, простой и надёжный канал связи ● Оптимизированный обмен сообщениями. ● Стабильная спецификация обмена сообщениями.

Slide 34

Slide 34 text

Шина. Плюсы ● Независимость технологий, развёртывания и масштабирования ● Стандартный, простой и надёжный канал связи ● Оптимизированный обмен сообщениями. ● Стабильная спецификация обмена сообщениями. ● Асинхронность обмена сообщениями и управление нагрузкой на систему.

Slide 35

Slide 35 text

Шина. Плюсы ● Независимость технологий, развёртывания и масштабирования ● Стандартный, простой и надёжный канал связи ● Оптимизированный обмен сообщениями. ● Стабильная спецификация обмена сообщениями. ● Асинхронность обмена сообщениями и управление нагрузкой на систему. ● Единая точка для управления версионированием и преобразованием форматов

Slide 36

Slide 36 text

Да ладно, и нет минусов?

Slide 37

Slide 37 text

Шина. Минусы ● Ниже скорость связи, особенно между уже совместимыми сервисами. ● Единая точка отказа, способная обрушить системы связи всей компании.

Slide 38

Slide 38 text

Шина. Минусы ● Ниже скорость связи, особенно между уже совместимыми сервисами. ● Единая точка отказа, способная обрушить системы связи всей компании. ● Большая сложность конфигурирования и поддержки. ● Шина так сложна, что для её управления вам потребуется целая команда.

Slide 39

Slide 39 text

Команда разработки/поддержки шины

Slide 40

Slide 40 text

Добавим в шину немножко логики?

Slide 41

Slide 41 text

И тут шаблон начинает выворачивать

Slide 42

Slide 42 text

Давай используем шину Разработчик Архитектор

Slide 43

Slide 43 text

No content

Slide 44

Slide 44 text

Но вернемся к микросервисам

Slide 45

Slide 45 text

Какие ваши проблемы они решают?

Slide 46

Slide 46 text

Попробуем отгадать ● Простота масштабирования ● Удобство параллельной разработки несколькими командами ● Переиспользование в разных продуктах ● ???

Slide 47

Slide 47 text

А как вообще создавать эти ваши микросервисы?

Slide 48

Slide 48 text

Микросервисы и DDD неразделимы

Slide 49

Slide 49 text

DDD бывает разный

Slide 50

Slide 50 text

DOMAIN Driven Design

Slide 51

Slide 51 text

DOMAIN Driven Design ● Bounded context X X

Slide 52

Slide 52 text

DOMAIN Driven Design ● Continuous integration Контракт

Slide 53

Slide 53 text

● Context map DOMAIN Driven Design

Slide 54

Slide 54 text

На уровне проектирования сервисов штука удобная

Slide 55

Slide 55 text

Но когда дело доходит до кода

Slide 56

Slide 56 text

DOMAIN Driven Design ● ООП ● Rich model ● Active records

Slide 57

Slide 57 text

DOMAIN Driven Design Entity Logic

Slide 58

Slide 58 text

Разделение сущностей и логики Entity DataObject Logic use

Slide 59

Slide 59 text

Анемичная модель. DATA Driven Design Entity DataObject Logic use

Slide 60

Slide 60 text

Внимание субъективное мнение

Slide 61

Slide 61 text

DaDD. Плюсы ● Немного проще писать тесты ● Меньше шансов создать сильную связку между классами сущностей ● Меньше кода

Slide 62

Slide 62 text

DaDD. Минусы ● На большом количестве сущностей проще скатиться в написание монстр- логики ● Уход от ООП (?)

Slide 63

Slide 63 text

Мы готовы писать микросервисы

Slide 64

Slide 64 text

Монолит разработчик разработчик разработчик разработчик разработчик разработчик

Slide 65

Slide 65 text

Есть еще проблемка

Slide 66

Slide 66 text

Разделяй и властвуй охреневай

Slide 67

Slide 67 text

Какие проблемы надо решать в микросервисах?

Slide 68

Slide 68 text

Какие проблемы надо решать в микросервисах? ● Свобода выбора стека или простота поддержки?

Slide 69

Slide 69 text

Какие проблемы надо решать в микросервисах? ● Свобода выбора стека или простота поддержки? ● Как не сожрать все ресурсы? ● Как собирать логи и как мониторить?

Slide 70

Slide 70 text

Какие проблемы надо решать в микросервисах? ● Свобода выбора стека или простота поддержки? ● Как не сожрать все ресурсы? ● Как собирать логи и как мониторить? ● Как обновлять api и не сломать совместимость? ● Как обновлять без даунтайма?

Slide 71

Slide 71 text

Какие проблемы надо решать в микросервисах? ● Свобода выбора стека или простота поддержки? ● Как не сожрать все ресурсы? ● Как собирать логи и как мониторить? ● Как обновлять api и не сломать совместимость? ● Как обновлять без даунтайма? ● Как масштабировать и балансировать нагрузку? ● Как отслеживать и останавливать распространение ошибок?

Slide 72

Slide 72 text

Какие проблемы надо решать в микросервисах? ● Свобода выбора стека или простота поддержки? ● Как не сожрать все ресурсы? ● Как собирать логи и как мониторить? ● Как обновлять api и не сломать совместимость? ● Как обновлять без даунтайма? ● Как масштабировать и балансировать нагрузку? ● Как отслеживать и останавливать распространение ошибок? ● Как не закопать бизнес-логику среди инфраструктурных классов? ● Как обновлять общие механизмы?

Slide 73

Slide 73 text

Какие проблемы надо решать в микросервисах? ● Свобода выбора стека или простота поддержки? ● Как не сожрать все ресурсы? ● Как собирать логи и как мониторить? ● Как обновлять api и не сломать совместимость? ● Как обновлять без даунтайма? ● Как масштабировать и балансировать нагрузку? ● Как отслеживать и останавливать распространение ошибок? ● Как не закопать бизнес-логику среди инфраструктурных классов? ● Как обновлять общие механизмы? ● Как не угробить расплывающуюся архитектуру? ● Как ...

Slide 74

Slide 74 text

Нет в жизни счастья

Slide 75

Slide 75 text

И как с этим жить?

Slide 76

Slide 76 text

Кажется, надо использовать голову...

Slide 77

Slide 77 text

… и инструменты

Slide 78

Slide 78 text

Свои инструменты надо знать отлично

Slide 79

Slide 79 text

На чем можно клепать микросервисы???

Slide 80

Slide 80 text

На чем можно клепать микросервисы java-dev?

Slide 81

Slide 81 text

На чем можно клепать микросервисы java-dev? ● Spring Boot ● Ratpack ● Micronaut ● Spark ● spring-fu ● etc.

Slide 82

Slide 82 text

Что у нас на сегодня? ● Spring...Boot, как он работает и как использовать его на полную ● Начнем смотреть Spring cloud из чего состоит какой он был и как изменился

Slide 83

Slide 83 text

Spring {Boot,Cloud} Workshop

Slide 84

Slide 84 text

Тренинг с конференции JPoint 2019 securi

Slide 85

Slide 85 text

Часть 1 Основы микросервисописания

Slide 86

Slide 86 text

Как будет проходить тренинг? Теория – мы рассказываем вы слушаете

Slide 87

Slide 87 text

Как будет проходить тренинг? Практика

Slide 88

Slide 88 text

All your classes All your pages and xmls Regular web.xml with spring dispatcher servlet, spring listener and security filter name Security filters, users and roles Spring MVC beans Application beans, Import security.xml The project structure

Slide 89

Slide 89 text

web.xml org.springframework.web.context.ContextLoaderListener springSecurityFilterChain org.springframework.web.filter.DelegatingFilterProxy springSecurityFilterChain /* mvc-dispatcher org.springframework.web.servlet.DispatcherServlet 1 mvc-dispatcher /

Slide 90

Slide 90 text

No content

Slide 91

Slide 91 text

No content

Slide 92

Slide 92 text

… contextClass …AnnotationConfigWebApplicationContext contextConfigLocation com.inwhite.conf.AppConfig …

Slide 93

Slide 93 text

Deployment →Use maven/gradle to build a war from that project →Copy it to webapps directory of tomcat

Slide 94

Slide 94 text

How does it work? User type in his browser: http://localhost:8080/myApp create Spring ContextLoaderListener Start tomcat start applicationContext In bootsrap In bootsrap Create filter mapping Create security filter login Create spring dispatcher servlet Delegate to Controller

Slide 95

Slide 95 text

Теперь давайте замочим XML

Slide 96

Slide 96 text

Жизнь без web.xml false Java Servlet Specification 3.+ Tomcat 7+

Slide 97

Slide 97 text

Что будем имплементировать вместо web.xml?

Slide 98

Slide 98 text

WebApplicationInitializer

Slide 99

Slide 99 text

ServletContainerInitializer

Slide 100

Slide 100 text

WebApplicationInitializer

Slide 101

Slide 101 text

ServletContainerInitializer

Slide 102

Slide 102 text

No content

Slide 103

Slide 103 text

§ 8.2.4 Shared libraries / runtimes pluggability The ServletContainerInitializer class is looked up via the jar services API. For each application, an instance of the ServletContainerInitializer is created by the container at application startup time. The framework providing an implementation of the ServletContainerInitializer MUST bundle in the META-INF/services directory of the jar file a file called javax.servlet.ServletContainerInitializer, as per the jar services API, that points to the implementation class of the ServletContainerInitializer. 3.+

Slide 104

Slide 104 text

Как? SPI tomcat |→ get javax.servlet.ServletContainerInitializer impl via SPI

Slide 105

Slide 105 text

§ 8.2.4 Shared libraries / runtimes pluggability The ServletContainerInitializer’s onStartup method get's a Set of Classes that either extend / implement the classes that the initializer expressed interest in or if it is annotated with any of the classes specified via the @HandlesTypes annotation. 3.+

Slide 106

Slide 106 text

Как? SPI tomcat |→ get javax.servlet.ServletContainerInitializer impl via SPI |→ get all MyInitializer classes (from @HandlesTypes)

Slide 107

Slide 107 text

Как? SPI tomcat |→ get javax.servlet.ServletContainerInitializer impl via SPI |→ get all WebApplicationInitializer classes (from @HandlesTypes) org.springframework.web.WebApplicationInitializer

Slide 108

Slide 108 text

Как? SPI tomcat |→ get javax.servlet.ServletContainerInitializer impl via SPI |→ get all WebApplicationInitializer classes (from @HandlesTypes) |→ call ServletContainerInitializer.onStartup(classes,servletCtx) according to @Order order

Slide 109

Slide 109 text

SPI org.springframework.web.SpringServletContainerInitializer content

Slide 110

Slide 110 text

§ Class ServiceLoader loader = ServiceLoader.load(ServletContainerInitializer.class) 6.+

Slide 111

Slide 111 text

§ Class ServiceLoader loader =ServiceLoader.load(ServletContainerInitializer.class) 6.+ Все имплементации ServletContainerInitializer

Slide 112

Slide 112 text

@HandlesTypes(WebApplicationInitializer.class) public class SpringServletContainerInitializer implements ServletContainerInitializer { ...

Slide 113

Slide 113 text

@HandlesTypes(WebApplicationInitializer.class) public class SpringServletContainerInitializer implements ServletContainerInitializer {

Slide 114

Slide 114 text

@HandlesTypes(WebApplicationInitializer.class) public class SpringServletContainerInitializer implements ServletContainerInitializer { @Override public void onStartup(Set> webAppInitializerClasses, ServletContext servletContext)

Slide 115

Slide 115 text

@HandlesTypes(WebApplicationInitializer.class) public class SpringServletContainerInitializer implements ServletContainerInitializer { @Override public void onStartup(Set> webAppInitializerClasses, ServletContext servletContext) ... AnnotationAwareOrderComparator.sort(initializers); ...

Slide 116

Slide 116 text

@HandlesTypes(WebApplicationInitializer.class) public class SpringServletContainerInitializer implements ServletContainerInitializer { @Override public void onStartup(Set> webAppInitializerClasses, ServletContext servletContext) ... AnnotationAwareOrderComparator.sort(initializers); ... initializers.forEach(initializer -> initializer.onStartup(ctx)); }

Slide 117

Slide 117 text

Дружок, дай ка мне ServletContainerInitializer tomcat 7 Spring Jar

Slide 118

Slide 118 text

Spring ServletContainer Initializer tomcat 7 Spring Jar

Slide 119

Slide 119 text

@HandlesTypes(WebApplicationInitializer.class) public class SpringServletContainerInitializer implements ServletContainerInitializer

Slide 120

Slide 120 text

WebApplicationInitializer W AI WAI tomcat 7 JARS

Slide 121

Slide 121 text

W AI WAI SpringServletContainerInitializer tomcat 7

Slide 122

Slide 122 text

public class WebStarter implements WebApplicationInitializer { @Override public void onStartup(ServletContext servletContext) throws ServletException { AnnotationConfigWebApplicationContext webContext = new AnnotationConfigWebApplicationContext(); webContext.register(WebConfig.class); ServletRegistration.Dynamic servlet = servletContext.addServlet("dispatcher", new DispatcherServlet(webContext)); servlet.setLoadOnStartup(1); AnnotationConfigWebApplicationContext appContext = new AnnotationConfigWebApplicationContext(); appContext.register(AppConfig.class); servletContext.addListener(new ContextLoaderListener(appContext)); servlet.addMapping("/*"); }

Slide 123

Slide 123 text

А попроще нельзя?

Slide 124

Slide 124 text

Можно, но со Spring Boot`ом – Демо

Slide 125

Slide 125 text

Как выглядит наш pom.xml org.springframework.boot spring-boot-starter-parent 2.1.4.RELEASE

Slide 126

Slide 126 text

org.springframework.boot spring-boot-starter-parent 2.1.4.RELEASE org.springframework.boot spring-boot-dependencies 2.1.4.RELEASE

Slide 127

Slide 127 text

No content

Slide 128

Slide 128 text

В чём проблема получить dependency management таким путём?

Slide 129

Slide 129 text

Это чужой parent!

Slide 130

Slide 130 text

No content

Slide 131

Slide 131 text

io.spring.platform platform-bom Brussels-SR2 pom import

Slide 132

Slide 132 text

Как выглядит наш build.gradle plugins { id "org.springframework.boot" version "2.1.4.RELEASE" } Пакует приложение

Slide 133

Slide 133 text

Как выглядит наш build.gradle plugins { id "org.springframework.boot" version "2.1.4.RELEASE" } dependencies { compile 'org.springframework.boot:spring-boot-starter-web' } Добавляем зависимости

Slide 134

Slide 134 text

Как выглядит наш build.gradle plugins { id "org.springframework.boot" version "2.1.4.RELEASE" } dependencies { compile 'org.springframework.boot:spring-boot-starter-web' } Automatic Dependency Management No Version

Slide 135

Slide 135 text

Как выглядит наш build.gradle plugins { id "org.springframework.boot" version "2.1.4.RELEASE" } dependencies { compile 'org.springframework.boot:spring-boot-starter-web' } dependencyManagement { imports { mavenBom 'org.springframework.cloud:spring-cloud-dependencies:Greenwich.RELEASE' } }

Slide 136

Slide 136 text

А я не понял

Slide 137

Slide 137 text

Web Starter ТАЩИТ!

Slide 138

Slide 138 text

Кто всё пакует org.springframework.boot spring-boot-maven-plugin

Slide 139

Slide 139 text

Jar как Jar, но если зайти внутрь...

Slide 140

Slide 140 text

No content

Slide 141

Slide 141 text

Анатомия SpringBoot Jar jar |- META-INF |- BOOT-INF |- libs |- classes |- org |- springframework |- boot

Slide 142

Slide 142 text

java -jar myapp.jar myapp.jar |- META-INF |- BOOT-INF |- libs |- classes |- org |- springframework |- boot MANIFEST.MF ... Main-Class: ??? ...

Slide 143

Slide 143 text

Перед запуском main – сформируй classpath

Slide 144

Slide 144 text

JarLauncher

Slide 145

Slide 145 text

Анатомия SpringBoot Jar myapp.jar |- META-INF |- BOOT-INF |- libs |- classes |- org |- springframework |- boot MANIFEST.MF ... Spring-Boot-Version: 1.5.3.RELEASE Implementation-Vendor: Pivotal Software, Inc. Main-Class: org.springframework.boot.loader.JarLauncher Start-Class:ru….ripper.OurMainClass Spring-Boot-Classes: BOOT-INF/classes/ Spring-Boot-Lib: BOOT-INF/lib/ ...

Slide 146

Slide 146 text

myapp.jar |- META-INF |- BOOT-INF |- libs |- classes |- org |- springframework |- boot Анатомия SpringBoot Jar MANIFEST.MF ... Spring-Boot-Version: 1.5.3.RELEASE Implementation-Vendor: Pivotal Software, Inc. Main-Class: org.springframework.boot.loader.JarLauncher Start-Class:ru….ripper.OurMainClass Spring-Boot-Classes: BOOT-INF/classes/ Spring-Boot-Lib: BOOT-INF/lib/ ...

Slide 147

Slide 147 text

MANIFEST.MF ... Spring-Boot-Version: 1.5.3.RELEASE Implementation-Vendor: Pivotal Software, Inc. Main-Class: org.springframework.boot.loader.JarLauncher Start-Class:ru….ripper.OurMainClass Spring-Boot-Classes: BOOT-INF/classes/ Spring-Boot-Lib: BOOT-INF/lib/ ... myapp.jar |- META-INF |- BOOT-INF |- libs |- classes |- org |- springframework |- boot Анатомия SpringBoot Jar JarLauncher

Slide 148

Slide 148 text

А кто прописывает манифест этому джару?

Slide 149

Slide 149 text

org.springframework.boot spring-boot-maven-plugin conference...OurMainClass MANIFEST.MF ... Start-Class: conference.spring.boot.ripper.OurMainClass ...

Slide 150

Slide 150 text

Как выбирается mainClass если его не указать Spring boot plugin сканирует проект – ищет мейны ● если есть только один – то это он :) ● если больше одного – смотрит где стоит @SpringBootApplication и выбирает его ● если @SpringBootApplication нет или >1 – ошибка о множественных main при сборке

Slide 151

Slide 151 text

Жмя и Работает executable jar для бабушки java -jar слишком сложно

Slide 152

Slide 152 text

Хочу executable jar: Maven org.springframework.boot spring-boot-maven-plugin true springBoot { executable = true } Gradle bootJar { launchScript() } Spring boot 1.x.x Spring boot 2.x.x

Slide 153

Slide 153 text

Demo. Executable jar

Slide 154

Slide 154 text

Внутренний мир executable Jar ● Бабушка хочет чтобы жмя и работало ● windows “click click” ● $ ./app.jar ● ...

Slide 155

Slide 155 text

Demo. jar structure

Slide 156

Slide 156 text

Как выглядит Jar? Script 0xf4ra -> а это ZIP! jar archive

Slide 157

Slide 157 text

Как выглядит Jar? Script 0xf4ra -> а это ZIP! jar archive Начало файла

Slide 158

Slide 158 text

Как выглядит Jar? Script 0xf4ra -> а это ZIP! jar archive Начало файла Начало zip архива

Slide 159

Slide 159 text

Где контекс? @SpringBootApplilcation class App { public static void main(String[] args) { SpringApplication.run(App.class,args); } }

Slide 160

Slide 160 text

Вот контекст! @SpringBootApplilcation class App { public static void main(String[] args) { ApplicationContext context = SpringApplication.run(App.class,args); } }

Slide 161

Slide 161 text

Разрешите представиться

Slide 162

Slide 162 text

Давайте поговорим о контексте Малыш знает про ClassPathXmlApplicationContext А какие контексты знаешь ТЫ?

Slide 163

Slide 163 text

Типы ConfigurableApplicationContext

Slide 164

Slide 164 text

Это я решаю какой контекст создать Я до создания контекста ещё много всего делаю, но об этом потом. SpringApplication

Slide 165

Slide 165 text

Web Context Generic Context

Slide 166

Slide 166 text

Web Context Generic Context Если в classpath есть Servlet.class...

Slide 167

Slide 167 text

Web Context Generic Context

Slide 168

Slide 168 text

Web Context Generic Context Если в classpath есть Servlet.class...

Slide 169

Slide 169 text

Если есть javax.servlet.Servlet ConfigurableWebApplicationContext + AnnotationConfigEmbedded WebApplicationContext AnnotationConfig ApplicationContext Иначе

Slide 170

Slide 170 text

И что там в контексте то?

Slide 171

Slide 171 text

Откуда 436 spring beans?

Slide 172

Slide 172 text

Откуда взялись все эти бины?

Slide 173

Slide 173 text

Не знаю как, но мы тоже так сделаем

Slide 174

Slide 174 text

Задание 1. Печатать предупреждение при вызове @Deprecated 2. Печатать время исполнения методов @Benchmark 3. * Отправить email на адрес alarm.email если вызвали @Deprecated или @Benchmark

Slide 175

Slide 175 text

AOP ● Joint Point ● Pontcut ● Advise ● Aspect

Slide 176

Slide 176 text

Pointcut ● execution ● within ● this ● target ● args ● bean ● @annotation

Slide 177

Slide 177 text

Пример @Aspect @Component public class TestAspect { @Pointcut("execution(* *.doSomething(..)) && args(list,..) ") public void callMethod(List list) { ... } }

Slide 178

Slide 178 text

Что за spring.factories ? § 44.1 Understanding auto-configured beans Under the hood, auto-configuration is implemented with standard @Configuration classes. Additional @Conditional annotations are used to constrain when the auto-configuration should apply. Usually auto-configuration classes use @ConditionalOnClass and @ConditionalOnMissingBean annotations. This ensures that auto-configuration only applies when relevant classes are found and when you have not declared your own @Configuration. You can browse the source code of spring-boot-autoconfigure to see the @Configuration classes that we provide (see theMETA-INF/spring.factories file).

Slide 179

Slide 179 text

Даёшь инверсию контроля для стартеров

Slide 180

Slide 180 text

@SpringBootApplication Всему голова

Slide 181

Slide 181 text

@SpringBootApplication

Slide 182

Slide 182 text

@SpringBootApplication → @ComponentScan → @Configuration → @EnableAutoConfiguration

Slide 183

Slide 183 text

@SpringBootApplication @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @SpringBootConfiguration @EnableAutoConfiguration @ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class), @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) }) public @interface SpringBootApplication { …

Slide 184

Slide 184 text

@SpringBootApplication @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @SpringBootConfiguration @EnableAutoConfiguration @ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class), @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) }) public @interface SpringBootApplication { …

Slide 185

Slide 185 text

@EnableAutoConfiguration @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @AutoConfigurationPackage @Import({EnableAutoConfigurationImportSelector.class}) public @interface EnableAutoConfiguration { String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration"; Class[] exclude() default {}; String[] excludeName() default {}; }

Slide 186

Slide 186 text

@EnableAutoConfiguration @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @AutoConfigurationPackage @Import({EnableAutoConfigurationImportSelector.class}) public @interface EnableAutoConfiguration { String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration"; Class[] exclude() default {}; String[] excludeName() default {}; }

Slide 187

Slide 187 text

@EnableAutoConfiguration @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @AutoConfigurationPackage @Import({EnableAutoConfigurationImportSelector.class}) public @interface EnableAutoConfiguration { String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration"; Class[] exclude() default {}; String[] excludeName() default {}; } ImportSelector

Slide 188

Slide 188 text

@EnableAutoConfiguration ImportSelector Web Starter Boot Starter … Starter Mongo Starter

Slide 189

Slide 189 text

Spring Factories Loader Jar/Starter spring.factories SpringFactoriesLoader

Slide 190

Slide 190 text

SpringFactoriesLoader static List loadFactories( Class factoryClass, ClassLoader cl ) static List loadFactoryNames( Class factoryClass, ClassLoader cl )

Slide 191

Slide 191 text

Даёшь инверсию контроля для стартеров

Slide 192

Slide 192 text

spring-boot-autoconfigure.jar/spring.factories org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\ org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\ org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\ org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration ….

Slide 193

Slide 193 text

spring-boot-autoconfigure.jar @Import(CacheConfigurationImportSelector.class) public class CacheAutoConfiguration {

Slide 194

Slide 194 text

CacheConfigurations private static final Map> MAPPINGS; static { Map> mappings = new HashMap>(); mappings.put(CacheType.GENERIC, GenericCacheConfiguration.class); mappings.put(CacheType.EHCACHE, EhCacheCacheConfiguration.class); mappings.put(CacheType.HAZELCAST, HazelcastCacheConfiguration.class); mappings.put(CacheType.INFINISPAN, InfinispanCacheConfiguration.class); mappings.put(CacheType.JCACHE, JCacheCacheConfiguration.class); mappings.put(CacheType.COUCHBASE, CouchbaseCacheConfiguration.class); mappings.put(CacheType.REDIS, RedisCacheConfiguration.class); mappings.put(CacheType.CAFFEINE, CaffeineCacheConfiguration.class); addGuavaMapping(mappings); mappings.put(CacheType.SIMPLE, SimpleCacheConfiguration.class); mappings.put(CacheType.NONE, NoOpCacheConfiguration.class); MAPPINGS = Collections.unmodifiableMap(mappings); }

Slide 195

Slide 195 text

Где то внутри CacheAutoConfiguration for (int i = 0; i < types.length; i++) { Imports[i] = CacheConfigurations.getConfigurationClass(types[i]); } return imports;

Slide 196

Slide 196 text

Захардкодили

Slide 197

Slide 197 text

И что, они всегда грузятся?

Slide 198

Slide 198 text

Спокойствие, есть @Conditional Они фильтруются

Slide 199

Slide 199 text

Почему бин то есть то нет? Какие условия?

Slide 200

Slide 200 text

@ConditionalOn***

Slide 201

Slide 201 text

Conditional и друзья @ConditionalOnBean @ConditionalOnClass @ConditionalOnCloudPlatform @ConditionalOnExpression @ConditionalOnJava @ConditionalOnJndi @ConditionalOnMissingBean @ConditionalOnMissingClass @ConditionalOnNotWebApplication @ConditionalOnProperty @ConditionalOnResource @ConditionalOnSingleCandidate @ConditionalOnWebApplication ...

Slide 202

Slide 202 text

Паззлер @Configuration @ConditionalOnWinterIsHere public class UndeadArmyConfiguration { @Bean public WinterUndeadArmy cursedArmy() { return new WinterUndeadArmy(); } @Bean @ConditionalOnWinterIsHere public DragonGlassFactory dragonGlassFactory() { return new DragonGlassFactory(); }

Slide 203

Slide 203 text

ConditionalOnPuzzler @Configuration public class КонфигурацияКазни { @Bean @ConditionalOnClass ({Мыло.class, Веревка.class}) @ConditionalOnMissingBean ({ФабрикаКазни. class}) public ФабрикаКазни виселицы() { return new ФабрикаВиселиц( "..."); } }

Slide 204

Slide 204 text

ConditionalOnPuzzler @Configuration public class КонфигурацияКазни { @Bean @ConditionalOnClass ({Мыло.class, Веревка.class}) @ConditionalOnMissingBean ({ФабрикаКазни. class}) public ФабрикаКазни виселицы() { return new ФабрикаВиселиц( "..."); } @Bean @ConditionalOnClass ({Стул.class, Ток.class}) @ConditionalOnMissingBean ({ФабрикаКазни. class}) public ФабрикаКазни cтулья() { return new ФабрикаЭлектрическихСтульев( "вж вж"); } }

Slide 205

Slide 205 text

ConditionalOnPuzzler @Configuration public class КонфигурацияКазни { @Bean @ConditionalOnClass ({Мыло.class, Веревка.class}) @ConditionalOnMissingBean ({ФабрикаКазни. class}) public ФабрикаКазни виселицы() { return new ФабрикаВиселиц( "..."); } @Bean @ConditionalOnClass ({Стул.class, Ток.class}) @ConditionalOnMissingBean ({ФабрикаКазни. class}) public ФабрикаКазни cтулья() { return new ФабрикаЭлектрическихСтульев( "вж вж"); } @Bean @ConditionalOnClass ({Гильотина.class, ХорошееНастроение. class}) @ConditionalOnMissingBean ({ФабрикаКазни. class}) public ФабрикаКазни гильотины() { return new ФабрикаГильотин( "хрусть хрусть"); } }

Slide 206

Slide 206 text

ConditionalOnPuzzler @Configuration public class КонфигурацияКазни { @Bean @ConditionalOnClass ({Мыло.class, Веревка.class}) @ConditionalOnMissingBean ({ФабрикаКазни. class}) public ФабрикаКазни виселицы() { return new ФабрикаВиселиц( "..."); } @Bean @ConditionalOnClass ({Стул.class, Ток.class}) @ConditionalOnMissingBean ({ФабрикаКазни. class}) public ФабрикаКазни cтулья() { return new ФабрикаЭлектрическихСтульев( "вж вж"); } @Bean @ConditionalOnClass ({Гильотина.class, ХорошееНастроение. class}) @ConditionalOnMissingBean ({ФабрикаКазни. class}) public ФабрикаКазни гильотины() { return new ФабрикаГильотин( "хрусть хрусть"); } } 1. ClassDefNotFound ? 2. Так вообще нельзя, не компилируется 3. Будет работать 4. Будет отлично работать

Slide 207

Slide 207 text

ConditionalOnPuzzler @Configuration public class КонфигурацияКазни { @Bean @ConditionalOnClass ({Мыло.class, Веревка.class}) @ConditionalOnMissingBean ({ФабрикаКазни. class}) public ФабрикаКазни виселицы() { return new ФабрикаВиселиц( "..."); } @Bean @ConditionalOnClass ({Стул.class, Ток.class}) @ConditionalOnMissingBean ({ФабрикаКазни. class}) public ФабрикаКазни cтулья() { return new ФабрикаЭлектрическихСтульев( "вж вж"); } @Bean @ConditionalOnClass ({Гильотина.class, ХорошееНастроение. class}) @ConditionalOnMissingBean ({ФабрикаКазни. class}) public ФабрикаКазни гильотины() { return new ФабрикаГильотин( "хрусть хрусть"); } } 1. ClassDefNotFound ? 2. Так вообще нельзя, не компилируется 3. Будет работать 4. Будет отлично работать

Slide 208

Slide 208 text

Потому что ASM

Slide 209

Slide 209 text

OnPropertyCondition @Conditional(OnPropertyCondition.class) public @interface ConditionalOnProperty { String[] value() default {}; String prefix() default ""; String[] name() default {}; String havingValue() default ""; boolean matchIfMissing() default false; boolean relaxedNames() default true; } Что если нужно изменить?

Slide 210

Slide 210 text

Люблю Spring Boot Но хочу Tomcat

Slide 211

Slide 211 text

public class WebStarter implements WebApplicationInitializer { @Override public void onStartup(ServletContext servletContext) throws ServletException { AnnotationConfigWebApplicationContext webContext = new AnnotationConfigWebApplicationContext(); webContext.register(WebConfig.class); ServletRegistration.Dynamic servlet = servletContext.addServlet("dispatcher", new DispatcherServlet(webContext)); servlet.setLoadOnStartup(1); AnnotationConfigWebApplicationContext appContext = new AnnotationConfigWebApplicationContext(); appContext.register(AppConfig.class); servletContext.addListener(new ContextLoaderListener(appContext)); servlet.addMapping("/*"); }

Slide 212

Slide 212 text

public class WebStarter implements WebApplicationInitializer { @Override public void onStartup(ServletContext servletContext) throws ServletException { AnnotationConfigWebApplicationContext webContext = new AnnotationConfigWebApplicationContext(); webContext.register(WebConfig.class); ServletRegistration.Dynamic servlet = servletContext.addServlet("dispatcher", new DispatcherServlet(webContext)); servlet.setLoadOnStartup(1); AnnotationConfigWebApplicationContext appContext = new AnnotationConfigWebApplicationContext(); appContext.register(AppConfig.class); servletContext.addListener(new ContextLoaderListener(appContext)); servlet.addMapping("/*"); }

Slide 213

Slide 213 text

public class WebStarter implements WebApplicationInitializer { @Override public void onStartup(ServletContext servletContext){ SpringApplication.run(RipperApplication.class); } }

Slide 214

Slide 214 text

public class WebStarter implements WebApplicationInitializer { @Override public void onStartup(ServletContext servletContext) { SpringApplication.run(RipperApplication.class); } } @SpringBootApplication public class RipperApplication { public static void main(String[] args) { SpringApplication.run(RipperApplication.class, args); } }

Slide 215

Slide 215 text

А в Tomcat не запустилось! В Tomcat`e не пашет

Slide 216

Slide 216 text

public class WebStarter implements WebApplicationInitializer{ @Override public void onStartup(ServletContext servletContext) throws ServletException { SpringApplication.run(RipperApplication.class); } } Tomcat в Tomcat`е

Slide 217

Slide 217 text

Читаем документацию

Slide 218

Slide 218 text

§ 85.1 Create a deployable war file @SpringBootApplication public class Application extends SpringBootServletInitializer { @Override protected SpringApplicationBuilder configure(SpringApplicationBuilder app) { return app.sources(Application.class); } public static void main(String[] args) throws Exception { SpringApplication.run(Application.class, args); } }

Slide 219

Slide 219 text

§ 85.1 Create a deployable war file @SpringBootApplication public class Application extends SpringBootServletInitializer { @Override protected SpringApplicationBuilder configure(SpringApplicationBuilder app) { return app.sources(Application.class); } public static void main(String[] args) throws Exception { SpringApplication.run(Application.class, args); } }

Slide 220

Slide 220 text

§ 85.1 Create a deployable war file @SpringBootApplication public class Application extends SpringBootServletInitializer { @Override protected SpringApplicationBuilder configure(SpringApplicationBuilder app) { return app.sources(Application.class); } public static void main(String[] args) throws Exception { SpringApplication.run(Application.class, args); } } Работает по разному

Slide 221

Slide 221 text

§ 85.1 Create a deployable war file @SpringBootApplication public class Application extends SpringBootServletInitializer { @Override protected SpringApplicationBuilder configure(SpringApplicationBuilder app) { return app.sources(Application.class); } public static void main(String[] args) throws Exception { SpringApplication.run(Application.class, args); } }

Slide 222

Slide 222 text

§ 85.1 Create a deployable war file @SpringBootApplication public class Application extends SpringBootServletInitializer { @Override protected SpringApplicationBuilder configure(SpringApplicationBuilder a) { return application.sources(Application.class); } public static void main(String[] args) throws Exception { SpringApplication.run(Application.class, args); } } Никогда не запустится в tomcat Только java -jar

Slide 223

Slide 223 text

§ 85.1 Create a deployable war file @SpringBootApplication public class Application extends SpringBootServletInitializer { @Override protected SpringApplicationBuilder configure(SpringApplicationBuilder a) { return application.sources(Application.class); } public static void main(String[] args) throws Exception { SpringApplication.run(Application.class, args); } } Без main не соберется см. maven/gradle плагины Обязательно

Slide 224

Slide 224 text

§ 85.1 Create a deployable war file @SpringBootApplication public class Application extends SpringBootServletInitializer { @Override protected SpringApplicationBuilder configure(SpringApplicationBuilder a) { return application.sources(Application.class); } public static void main(String[] args) throws Exception { SpringApplication.run(Application.class, args); } } Опционально

Slide 225

Slide 225 text

§ 85.1 Create a deployable war file @SpringBootApplication public class Application extends SpringBootServletInitializer { @Override protected SpringApplicationBuilder configure(SpringApplicationBuilder a) { return application.sources(Application.class); } public static void main(String[] args) throws Exception { SpringApplication.run(Application.class, args); } } Никогда не запустится в embedded режиме Только в Tomcat контейнере Опционально

Slide 226

Slide 226 text

Анатомия War .war |- META-INF |- WEB-INF |- lib |- classes |- org/springframework/boot/loader |- WarLauncher and friends

Slide 227

Slide 227 text

А как убрать tomcat из tomcat? If you are using a version of Gradle that supports compile only dependencies (2.12 or later), you should continue to use providedRuntime. Among other limitations, compileOnly dependencies are not on the test classpath so any web-based integration tests will fail.

Slide 228

Slide 228 text

Анатомия War .war |- META-INF |- WEB-INF |- lib |- lib-provided |- classes |- org/springframework/boot/loader |- WarLauncher and friends

Slide 229

Slide 229 text

Анатомия SpringBoot Jar/War jar |- META-INF |- BOOT-INF |- libs |- classes |- org/springframework/boot/loader |- JarLauncher and friends war |- META-INF |- WEB-INF |- lib |- lib-provided |- classes |- org/springframework/boot/loader |- WarLauncher and friends

Slide 230

Slide 230 text

Jar стал похож на War

Slide 231

Slide 231 text

No content

Slide 232

Slide 232 text

Замочили web.xml

Slide 233

Slide 233 text

Замочили web.xml Вместе с Tomcat`ом Вопросы?

Slide 234

Slide 234 text

Вспомним Spring MVC Перед самым важным

Slide 235

Slide 235 text

@RestController("/examine") Ошибку видишь? А она есть

Slide 236

Slide 236 text

@RestController("/examine") Это имя spring bean, не http path И это даже может работать: ● Если нет ни одного контроллера с путём (всегда будет вызываться) ● Если потом указали полный путь в @RequestMapping

Slide 237

Slide 237 text

@RequestMapping и его братья Управляет маршрутизацией запросов в метод контроллера. Маршрутизирует по: ● name/value – сам http path ● method – http method ● params ● headers

Slide 238

Slide 238 text

@RequestMapping и его братья @PostMapping("/examine") public CheckedExam ex`( @RequestBody SolvedExam title) { } @RequestMapping (path = "/examine", method = POST) public CheckedExam ex2( @RequestBody SolvedExam title) { } @RequestMapping (path = "/examine", method = POST, headers = {"my-app=appid"}) public CheckedExam ex3( @RequestBody SolvedExam title) { } @GetMapping(path = "/examine", headers = {"content-type=application/json"}) public CheckedExam ex3() { } @GetMapping(path = "/examine", produces = MimeTypeUtils. APPLICATION_JSON_VALUE) public CheckedExam ex3() { }

Slide 239

Slide 239 text

@RequestMapping и его братья @PostMapping("/examine") public CheckedExam ex`( @RequestBody SolvedExam title) { } @RequestMapping (path = "/examine", method = POST) public CheckedExam ex2( @RequestBody SolvedExam title) { } @GetMapping(path = "/examine", headers = {"content-type=application/json"}) public CheckedExam ex3() { } @GetMapping(path = "/examine", produces = APPLICATION_JSON_VALUE) public CheckedExam ex3() { } @GetMapping(path = "/examine", produces = APPLICATION_JSON_VALUE) public CheckedExam ex4() { }

Slide 240

Slide 240 text

@RequestMapping и его братья @PostMapping("/examine") public CheckedExam ex`( @RequestBody SolvedExam title) { } @RequestMapping (path = "/examine", method = POST) public CheckedExam ex2( @RequestBody SolvedExam title) { } @GetMapping(path = "/examine", headers = {"content-type=application/json"}) public CheckedExam ex3() { } @GetMapping(path = "/examine", produces = APPLICATION_JSON_VALUE) public CheckedExam ex3() { } @GetMapping(path = "/examine", produces = APPLICATION_JSON_VALUE) public CheckedExam ex4() { }

Slide 241

Slide 241 text

@RequestMapping и его братья //curl -XPOST /examine -d '{ "title": {..} }' @PostMapping("/examine") public CheckedExam ex`( @RequestBody SolvedExam exam) { } //curl -XGET /examine/ mytitle @GetMapping("/examine/{title}") public CheckedExam ex3( @PathVariable String title) { } //curl -XGET /examine/mytitle ?debug=true @GetMapping("/examine/{title}") public CheckedExam ex3( @PathVariable String title, @RequestParam Boolean debug) { }

Slide 242

Slide 242 text

@RequestMapping автовпрыскивание @PostMapping("/examine") public CheckedExam ex6(HttpServletRequest httpServletRequest, Authentication auth, UserDetails user, etc ) { }

Slide 243

Slide 243 text

Controllers endpoints in logs since Spring 5 logging.level: //print mapped controllers org.springframework.web.servlet.mvc.method.annotation: TRACE web: DEBUG //print requests to console

Slide 244

Slide 244 text

Наконец то будем писать код!

Slide 245

Slide 245 text

Задание 0 Напишем стартер DoD: 1. Все контроллеры помеченые @FrontendController аннотацией должны обворачивать возвращаемый результат в дополнительный Json { "result": { оригинальный_json } } 2. https://github.com/lavcraft/spring-boot-and-cloud-ripper-2019 3.

Slide 246

Slide 246 text

Talk is cheap. Show me the code Linus Torvalds https://github.com/lavcraft/spring-boot-and-cloud-ripper-2019

Slide 247

Slide 247 text

Задание 1. Напишем Экзаминатора public static void main(String[] args){ SpringApplication.run( ExaminatorApplication.class, args); }

Slide 248

Slide 248 text

{ "География":5, "Физика" :3 } Физика Математика Теология Не грешно ли лезть в атом? Теорема Пифагора Неравенство Коши E=? Количество вопросов Количество вопросов Экзаминатор

Slide 249

Slide 249 text

С чего начинают строить микросервис →Контроллеры →Сервисы →Dao →Model

Slide 250

Slide 250 text

С чего начинают строить микросервис →Контроллеры →Сервисы →Dao →Model – поскольку модель используется на всех слоях, пожалуй лучше начинать с неё

Slide 251

Slide 251 text

in: { "student": "Борисов Евгений", "title": "Экзамен на JokerConf", "sections": [{ "title": "Java", "description": "простые вопросы по java", "exercises": [ { "question": "разница между spring string и swing", "answer": "без spring`а не обойтись" }, { "question": "разница между final finally finalize", "answer": "за finalize отрывают руки" } ]}, { "title": "философия", "description": "сложные вопросы по философии", "exercises": [{ "question": "В чем смысл жизни", "answer": "42" }, { "question": "Что раньше, яйцо или курица", "answer": "петух" }] }] } out: { "mark": 99, "title": "Экзамен на JokerConf", "sections": [{ "title": "Java", "description": "простые вопросы по java", "exercises": [ { "question": "разница между spring string и swing", "answer": "без spring`а не обойтись" }, { "question": "разница между final finally finalize", "answer": "за finalize отрывают руки" } ]}, { "title": "философия", "description": "сложные вопросы по философии", "exercises": [{ "question": "В чем смысл жизни", "answer": "42" }, { "question": "Что раньше, яйцо или курица", "answer": "петух" }] }] }

Slide 252

Slide 252 text

Data model - задание 1.1* Придумайте архитектуру модели, которая позволит написать Сервис: - принимающий на вход объект SolvedExam - отдающий CheckedExam с оценкой - Должны проходить тесты @Test public void checkExamineContract() throws Exception { ... mockMvc.perform(post("/examine")) ... } Use @RestController and @RequestMapping > @*Mapping Luke

Slide 253

Slide 253 text

Data model - задание 1.1* Придумайте архитектуру модели, которая позволит написать Сервис: - принимающий на вход объект SolvedExam - отдающий CheckedExam с оценкой - Смотрите в src/test/resources/*.json - Должны проходить тесты @Test public void checkExamineContract() throws Exception { ... mockMvc.perform(post("/examine")) ... } Use @RestController and @RequestMapping > @*Mapping Luke

Slide 254

Slide 254 text

Зло наследования

Slide 255

Slide 255 text

Композиция намного лучше

Slide 256

Slide 256 text

У композиции нет границ

Slide 257

Slide 257 text

У композиции нет границ

Slide 258

Slide 258 text

Lombok – composition / delegate and friends Annotation Processor Работает на этапе компиляции Генерит код, чтобы мы не писали Делает джаву более похожим на нормальный язык

Slide 259

Slide 259 text

Про lombok, модели и не только @Data – POJO (@Getter, @Setter, @ToString, @EqualsAndHashcode) @Value – immutable POJO @AllArgumentConstruct(onConstructor = @_(@Autowired))

Slide 260

Slide 260 text

Про lombok, модели и не только @Data – POJO (@Getter, @Setter, @ToString, @EqualsAndHashcode) @Value – immutable POJO @AllArgumentConstruct(onConstructor = @_(@Autowired)) @RequireArgumentConstructor /@NoArgumentConstructor @Builder / @Singular @Delegate – примерно как в груви @SneakyThrows @Slf4j / @Log4j / …

Slide 261

Slide 261 text

Теперь давайте разбираться Джэксоном

Slide 262

Slide 262 text

Как Джексон пишет в джейсон 1. Использует Java Getters a. Методы начинающиеся с Get 2. @JsonIgnore – игнорируем Getter 3. Нет ни одного Getter – падает

Slide 263

Slide 263 text

Как Джексон пишет в объект 1. Нет конструктора с @ConstructProperies → выставляет через Setters → если нет Setter и есть Getter – выставляет напрямую в филды → это все только при наличии пустого конструктора 2. Есть конструктор с @ConstructProperies → выставляет значение через него 3. После зачем то вызовет все геттеры * Но если есть то @JsonIgnore всё по другому * Это поведение по умолчанию

Slide 264

Slide 264 text

Меняем дефолтное поведение @JsonIgnoreProperties @JsonIgnoreType @JsonIgnore @JsonProperty

Slide 265

Slide 265 text

Что не так с JSR 310?

Slide 266

Slide 266 text

→ Если вы настраиваете руками: ObjectMapper mapper = new ObjectMapper() .registerModule( new ParameterNamesModule()) .registerModule( new Jdk8Module()) .registerModule( new JavaTimeModule()); → Или так: mapper.findAndRegisterModules(); Не забыть зависимости: compile 'com.fasterxml.jackson.module:jackson-module-parameter-names' compile 'com.fasterxml.jackson.datatype:jackson-datatype-jdk8' compile 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310' C последних версий есть поддержка Java8

Slide 267

Slide 267 text

Достаточно одних зависимостей Если вы работаете с Spring Boot 1.x.x

Slide 268

Slide 268 text

Вообще ничего не нужно Если вы работаете с Spring Boot 2.x.x

Slide 269

Slide 269 text

Как Spring MVC работает с Джексоном Напишите метод который принимает json и класс, а возвращает объект данного класса Пробуем использовать objectMapper Jackson2

Slide 270

Slide 270 text

@DateTimeFormat Ну вы в курсе… А ещё можно в application.properties

Slide 271

Slide 271 text

Кстати о сериалайзерах Давайте как то без них, по возможности

Slide 272

Slide 272 text

Кто использует Jackson в мире Spring MVC 1. ClassLoader 2. Dispatcher Servlet 3. Tomcat 4. BeanPostProcessor

Slide 273

Slide 273 text

Кто использует Jackson в мире Spring MVC 1. ClassLoader 2. Dispatcher Servlet 3. Tomcat 4. BeanPostProcessor

Slide 274

Slide 274 text

Задание 2 Микросервис – Теологии 1. Добавлять вопросы по теологии … (CRUD) 2. Получать нужное количество рандомальных вопросов 3. Тест должен проходить @Test public void should_return_random_exercise() throws Exception { mvc.perform(get("/exercise/random?count=3") .contentType( APPLICATION_JSON) ) … Use JpaRepository and @RequestMapping Luke

Slide 275

Slide 275 text

{ "География":5, "Физика" :3 } Физика Математика Теология Не грешно ли лезть в атом? Теорема Пифагора Неравенство Коши ваы Количество вопросов Количество вопросов Экзаминатор Person p = restTemplate.getForObject("/{name}/details", Person.class, name); Для связи сервисов используем RestTemplate

Slide 276

Slide 276 text

Конфликт портов — relaxed properties 1. server.port в application.properties 2. export SERVER_PORT=8081 3. java -jar --server.port=8081 4. SPRING_APPLICATION_JSON = '{"server":{"port":8081}}'

Slide 277

Slide 277 text

in: { "student": "Борисов Евгений", "title": "Экзамен на JokerConf", "sections": [{ "title": "Java", "description": "простые вопросы по java", "exercises": [ { "question": "разница между spring string и swing", "answer": "без spring`а не обойтись" }, { "question": "разница между final finally finalize", "answer": "за finalize отрывают руки" } ] }, { "title": "философия", "description": "сложные вопросы по философии", "exercises": [{ "question": "В чем смысл жизни", "answer": "42" }, { "question": "Что раньше, яйцо или курица", "answer": "петух" }] }] }

Slide 278

Slide 278 text

compile 'org.springframework.data:spring-data-rest-webmvc' Подключаем Spring Data Rest

Slide 279

Slide 279 text

Подключаем Spring Data Rest compile 'org.springframework.data:spring-data-rest-webmvc' или compile 'org.springframework.boot:spring-boot-starter-data-rest'

Slide 280

Slide 280 text

Подключаем Spring Data Rest compile 'org.springframework.data:spring-data-rest-webmvc' или compile 'org.springframework.boot:spring-boot-starter-data-rest'

Slide 281

Slide 281 text

Дальше пишем Entity + Repository Which repositories get exposed by defaults? Name Description DEFAULT Exposes all public repository interfaces but considers @Repository/@RestResource’s `exported flag ALL Exposes all repositories independently of type visibility and annotations ANNOTATION Only repositories annotated with @Repository/@RestResource are exposed, unless their exported flag is set to false VISIBILITY Only public repositories annotated are exposed

Slide 282

Slide 282 text

Как поменять стратегию @Component public class MyWebConfiguration extends RepositoryRestConfigurerAdapter { @Override public void configureRepositoryRestConfiguration( RepositoryRestConfiguration config) { config.setRepositoryDetectionStrategy( ALL); } }

Slide 283

Slide 283 text

Как задать URL @Configuration class CustomRestMvcConfiguration { @Bean public RepositoryRestConfigurer repositoryRestConfigurer() { return new RepositoryRestConfigurerAdapter() { @Override public void configureRepositoryRestConfiguration( RepositoryRestConfiguration config) { configuration.setBasePath( "/api") } }; } }

Slide 284

Slide 284 text

Как задать URL @Configuration class CustomRestMvcConfiguration { @Bean public RepositoryRestConfigurer repositoryRestConfigurer() { return new RepositoryRestConfigurerAdapter() { @Override public void configureRepositoryRestConfiguration( RepositoryRestConfiguration config) { configuration.setBasePath( "/api") } }; } } Или в том же RepositoryRestConfigurerAdapter прописать в application.properties - spring.data.rest.base-path=/api

Slide 285

Slide 285 text

Spring Data Rest official supports →Spring Data JPA →Spring Data MongoDB →Spring Data Neo4j →Spring Data GemFire →Spring Data Cassandra

Slide 286

Slide 286 text

@RepositoryRestResource @RepositoryRestResource (collectionResourceRel = "people", path = "people") public interface PersonRepository extends MongoRepository { @RestResource(path = "byname") List findByLastName(@Param( "name") String name); }

Slide 287

Slide 287 text

URL’s и методы localhost:8080/exercise – список всех (GET) localhost:8080/exercise/1 – дай человека с айдишником 1 (GET) localhost:8080/exercise/1 – стереть с айдишником 1 (DELETE) localhost:8080/exercise/1 – заменить с айдишником 1 (PUT) localhost:8080/exercise/1 – проапдэйтить с айдишником 1 (PATCH) localhost:8080/exercise/search/findByName?name=Lanister

Slide 288

Slide 288 text

{ "География":5, "Физика" :3 } Физика Математика Теология Не грешно ли лезть в атом? Теорема Пифагора Неравенство Коши ваы Количество вопросов Количество вопросов Экзаминатор

Slide 289

Slide 289 text

Задание 3 Связать сервисы Экзаменатора и Предметы ● Запустить и проверить самим ● Должен отдаваться запрос с ответами другого сервиса { "География":5, "Физика" :3 }

Slide 290

Slide 290 text

--server.port Конфликт портов решается с помощью relaxed properties export SERVER_PORT=8081 java -jar --server.port=8081 SPRING_APPLICATION_JSON = '{"server":{"port":8081}}'

Slide 291

Slide 291 text

RestTemplate ● you can create it even with new / or inject configured bean ● postForEntity / postForObject/ getForEntity / getForObject restTemplate.getForObject( "http://"+serviceName+"/exercice/random?count=" + number, Exercice[].class); ● exchange restTemplate.exchange(url.toString(), HttpMethod.POST, entity, String.class);

Slide 292

Slide 292 text

Шаринг кода модель/бизнес логика/инфраструктурный код ● Шарить ● Или не шарить

Slide 293

Slide 293 text

Подход №1 - общий код Зачем разбивать микросервис на модули? → Java API для сервисов → фиксация контракта на уровне зависимостей языка → утилитарная функция, избавления от бойлерплейта

Slide 294

Slide 294 text

Подход №1 - общий код project |- project-sdk |- project-app |- project-...

Slide 295

Slide 295 text

Подход №1 - общий код project |- project-sdk |- project-app |- project-api |- project-domain |- project-... Пфф

Slide 296

Slide 296 text

Подход №1 - общий код project |- project-sdk |- project-app |- project-api |- project-domain |- project-... Пфф KISS

Slide 297

Slide 297 text

Подход №2 - общий контракт → разделение кода и контракта → поставка контракта отдельно

Slide 298

Slide 298 text

Обратимся к истории → REST подход ○ → RPC подход ○

Slide 299

Slide 299 text

Обратимся к истории → REST подход ○ анархия и рекомендации → RPC подход ○

Slide 300

Slide 300 text

Обратимся к истории → REST подход ○ анархия и рекомендации → RPC подход ○ jax-ws/jax-rpc ○ corba ○ json rpc ○ ○

Slide 301

Slide 301 text

Обратимся к истории → REST подход ○ анархия и рекомендации → RPC подход ○ jax-ws/jax-rpc ○ corba ○ json rpc ○ thrift ○ protobuf/grpc ○ etc

Slide 302

Slide 302 text

Задание 5 ● пишем SDK для вызова микросервиса по теологии ● и тесты для него ● тестируем контракт ● тестируем взаимодействие ○ WireMock/Spring MockServer ○ Spring Boot Test ○ Context Scanning behaviour Тест SDK Тест Контракта Тест Взаимодействия

Slide 303

Slide 303 text

Разбиваем микросервис на модули Кому отсыпать наносервисов?

Slide 304

Slide 304 text

Конец 1й части приходите на Spring Boot Ripper

Slide 305

Slide 305 text

Тренинг с конференции JPoint 2019

Slide 306

Slide 306 text

Часть 2 Микросервисы при масштабировании

Slide 307

Slide 307 text

{ "География":5, "Физика" :3 } Физика Математика Теология Не грешно ли лезть в атом? Теорема Пифагора Неравенство Коши Энтропия не? Количество вопросов Количество вопросов Экзаминатор

Slide 308

Slide 308 text

{ "География":5, "Физика" :3 } Физика Математика Теология Теорема Пифагора Неравенство Коши ваы Количество вопросов Количество вопросов Экзаминатор Бог Не грешно ли лезть в атом?

Slide 309

Slide 309 text

Матмематика – сервис ● Сделать новый модуль ● Реализовать метод "/exercise/random" ● Возвращать список автогенерируемых упражнение (как в Теологии)

Slide 310

Slide 310 text

Как воткнуть в Examinator?

Slide 311

Slide 311 text

Как воткнуть в Examinator math-service? exercises: urls: "theology" : "http://localhost:8080/"

Slide 312

Slide 312 text

Как воткнуть в Examinator math-service? exercises: urls: "theology" : "http://localhost:8080/" "math" : "http://localhost:8082/" Потому что на 8081 Examinator

Slide 313

Slide 313 text

Как воткнуть в Examinator math-service? exercises: urls: "theology" : "http://localhost:8080/" "math" : "http://localhost:8082/" "examinator": "http://localhost:8081/" "..." : "http://localhost:8083/" Service Registry в application.yml

Slide 314

Slide 314 text

А как шарить service registry в yml?

Slide 315

Slide 315 text

Service Registry

Slide 316

Slide 316 text

{ "География":5, "Физика" :3 } Физика Математика Количество вопросов Количество вопросов Экзаминатор Экзаминатор Теология Service Registry

Slide 317

Slide 317 text

{ "География":5, "Физика" :3 } Физика Математика Количество вопросов Количество вопросов Экзаминатор Экзаминатор Теология Service Registry Clients Server

Slide 318

Slide 318 text

Service Registry

Slide 319

Slide 319 text

Что хранится в Service Registry? ● serviceId ● Ip адрес и порт ● Данные о хелсчеках ● Метаданные ○ Данные о геозонах ○ Пользовательские данные

Slide 320

Slide 320 text

Кстати о хелсчеках Service Service registry Heartbeat

Slide 321

Slide 321 text

Кстати о хелсчеках Service Service registry HealthCheck

Slide 322

Slide 322 text

/actuator/health { "status": "UP", }

Slide 323

Slide 323 text

/actuator/health management: endpoint: health: show-details: "ALWAYS"

Slide 324

Slide 324 text

/actuator/health { "status": "UP", "details": { "diskSpace": { "status": "UP", "details": { "total": 499963174912, "free": 354837377024, "threshold": 10485760 } }, "refreshScope": { "status": "UP" }, ….

Slide 325

Slide 325 text

Можно конечно и хелсчек eureka: client: healthcheck: enabled: true

Slide 326

Slide 326 text

Service Eureka Marathon Marathon Lb

Slide 327

Slide 327 text

Eureka Server and Client compile 'org.springframework.cloud:spring-cloud-starter-eureka-server' compile 'org.springframework.cloud:spring-cloud-starter-eureka'

Slide 328

Slide 328 text

Eureka Server and Client compile 'org.springframework.cloud:spring-cloud-starter-eureka-server' compile 'org.springframework.cloud:spring-cloud-starter-eureka' С Greenwich релиза compile 'org.springframework.cloud:spring-cloud-starter-netflix-eureka-client' compile 'org.springframework.cloud:spring-cloud-starter-netflix-eureka-server' Spring Boot 1.x.x Spring Boot 2.x.x

Slide 329

Slide 329 text

Собственный Eureka Server @EnableEurekaServer @SpringBootApplication public class EurekaServer { public static void main(String[] args) { SpringApplication.run(EurekaServer.class, args); } } server.port: 8761 spring.application.name: registry eureka: client.register-with-eureka: false server.enable-self-preservation: false

Slide 330

Slide 330 text

Переводим на Eureka ● Создаём модуль eureka-server compile 'org.springframework.cloud:spring-cloud-starter-eureka-server' compile 'org.springframework.cloud:spring-cloud-starter-eureka' Or compile 'org.springframework.cloud:spring-cloud-starter-netflix-eureka-server' compile 'org.springframework.cloud:spring-cloud-starter-netflix-eureka-client'

Slide 331

Slide 331 text

Переводим на Eureka ● Подключаем новый bom enforcedPlatform( "org.springframework.cloud: spring-cloud-dependencies:Greenwich.RELEASE"), ● Создаём модуль eureka-server compile 'org.springframework.cloud:spring-cloud-starter-eureka-server' Or compile 'org.springframework.cloud:spring-cloud-starter-netflix-eureka-server' ● Интегрируем клиента (examinator-service, theology-service, math-service) compile 'org.springframework.cloud:spring-cloud-starter-eureka' Or compile 'org.springframework.cloud:spring-cloud-starter-netflix-eureka-client'

Slide 332

Slide 332 text

Переводим на Eureka @EnableDiscoveryClient vs @EnableEurekaClient eureka.client.service-url.default-zone: http://127.0.0.1:8761/eureka/ spring.application.name: EXAMINATOR @Никаких Аннотация не нужно в 2хх eureka.client.service-url.default-zone: http://127.0.0.1:8761/eureka/ spring.application.name: EXAMINATOR Spring Boot 1.x.x Spring Boot 2.x.x

Slide 333

Slide 333 text

@EnableDiscoveryClient Будет включен по умолчанию при добавлении стартера c Edgware spring-cloud release train application.yml: server.port: 8081 spring.application.name: examinator eureka.client.service-url.defaultZone:http://localhost:8671/eureka

Slide 334

Slide 334 text

@EnableEurekaServer Будет включен по умолчанию при добавлении стартера c Edgware spring-cloud release train application.yml: server.port: 8761 spring.application.name: registry eureka: client.register-with-eureka= false

Slide 335

Slide 335 text

@EnableEurekaServer open http://localhost:8761

Slide 336

Slide 336 text

И как это использовать? Как переделать Examinator, чтобы он соблюдал open close?

Slide 337

Slide 337 text

Кто это у нас там спрятался? Смотрим какие сервисы загрузились $ http :8082/health { "description": "Remote status from Eureka server", "status": "DOWN" } { "description": "Spring Cloud Eureka Discovery Client", "status": "UP" } Spring Boot 1.x.x

Slide 338

Slide 338 text

Кто это у нас там спрятался? Выключаем security для управляющий API management: security: enabled: false Теперь $ http :8082/health Spring Boot 1.x.x

Slide 339

Slide 339 text

{ "description": "Spring Cloud Eureka Discovery Client", "discoveryComposite": { "description": "Spring Cloud Eureka Discovery Client", "discoveryClient": { "description": "Spring Cloud Eureka Discovery Client", "services": [ "examinator-service", "math-service", "theology-service" ], "status": "UP" }, "eureka": { "applications": { "EXAMINATOR-SERVICE": 1, "MATH-SERVICE": 1, "THEOLOGY-SERVICE": 1 }, "description": "Remote status from Eureka server", "status": "UP" }, "status": "UP" }, "diskSpace": { "free": 190254260224, "status": "UP", "threshold": 10485760, "total": 499055067136 }, ... Spring Boot 1.x.x

Slide 340

Slide 340 text

Кто это у нас там спрятался? application.yml management: endpoints: web: exposure: include: '*' Spring Boot 2.x.x

Slide 341

Slide 341 text

Кто это у нас там спрятался? Смотрим какие сервисы загрузились $ http :8082/actuator/health { "status": "UP" } $ http :8082/actuator/metrics ... $ http :8082/actuator ... Spring Boot 2.x.x

Slide 342

Slide 342 text

Как обратиться к сервисам по имени? restTemplate.getForObject( "http://"+serviceName+"/exercice/random?count=" + number, Exercice[].class );

Slide 343

Slide 343 text

True Discovery ● Написать контроллер, который возвращает все зарегистрированные сервисы ● Запустить несколько сервисов одного типа, посмотреть результат @Autowired private DiscoveryClient discoveryClient; discoveryClient.getServices() discoveryClient.getInstances("theology")

Slide 344

Slide 344 text

True Discovery ● Включить логику резолва сервиса в адресе запроса Use @LoadBalanced or LoadBalancerInterceptor Luke

Slide 345

Slide 345 text

Health checks starting

Slide 346

Slide 346 text

Health checks http available starting

Slide 347

Slide 347 text

Health checks app available http available starting

Slide 348

Slide 348 text

Health checks marathon window app available http available starting

Slide 349

Slide 349 text

Health checks unavailable window marathon window app available http available available window starting

Slide 350

Slide 350 text

Health checks unavailable window marathon window app available http available started available window starting working

Slide 351

Slide 351 text

Self preservation

Slide 352

Slide 352 text

Self preservation Service Registry 2 Service A Instance 1 Service B Instance 1 Service A Instance 2 Service B Instance 2 Service Registry 1

Slide 353

Slide 353 text

Self preservation Service Registry 2 Service A Instance 1 Service B Instance 1 Service A Instance 2 Service B Instance 2 Service Registry 1

Slide 354

Slide 354 text

Self preservation eureka: server.enable-self-preservation: false

Slide 355

Slide 355 text

Discovery и Load Balancing Две стороны одного и того же

Slide 356

Slide 356 text

Discovery и Load Balancing Две стороны одного и того же Server Side vs Client Side

Slide 357

Slide 357 text

357 Service Client Registry-aware HTTP Client Service Registry Service Instance 1 Service Instance N Service Instance ... Load balance request Client side discovery Ribbon + Eureka Discovery client

Slide 358

Slide 358 text

358 Service Client Service Registry Service Instance 1 Service Instance N Service Instance ... Load balance request Router/Proxy Server side discovery

Slide 359

Slide 359 text

сервис ошибки задержки сети балансировка конфигурация инфраструктура

Slide 360

Slide 360 text

Резюмируем Discovery

Slide 361

Slide 361 text

Разберемся HTTP_PORT MANAGEMENT_PORT HTTP_ADVERTIZED_PORT MANAGEMENT_ADVERTIZED_PORT Внутри контейнера Внутренние порты Внешние порты App in Docker Во вне

Slide 362

Slide 362 text

@EnableEurekaServer open http://localhost:8761 HTTP_ADVERTIZED_PORT

Slide 363

Slide 363 text

Немного о HTTP Clients RestTemplate/Feign/OkHttp/Apache HTTP/Java HTTP

Slide 364

Slide 364 text

Feign Client с обратной стороны стороны @RestController @RequestMapping(value = "/v0/forms/latestByUserId") public class FormsController { @GetMapping Form get(@RequestHeader("x-userid") String userId) { return new Form(..) } }

Slide 365

Slide 365 text

Feign Client с другой стороны @RestController @RequestMapping(value = "/v0/forms/latestByUserId") public class FormsController { @GetMapping Form get(@RequestHeader("x-userid") String userId) { return new Form(..) } }

Slide 366

Slide 366 text

Feign Client @FeignClient( name = "myApplicationName", url = "${config.myApplicationName}") @RequestMapping(value = "/v0/forms/latestByUserId") public interface FormsClient { @GetMapping Form get(@RequestHeader("x-userid") String userId); }

Slide 367

Slide 367 text

Feign Client @FeignClient( name = "myApplicationName", url = "${config.myApplicationName}") @RequestMapping(value = "/v0/forms/latestByUserId") public interface FormsClient { @GetMapping Form get(@RequestHeader("x-userid") String userId); }

Slide 368

Slide 368 text

Блеск и нищета RestTemplate restTemplate.exchange( "/cik", HttpMethod.GET, HttpEntity.newInstance(headers), Form[].class).body

Slide 369

Slide 369 text

Блеск и нищета RestTemplate restTemplate.exchange( "/forms", HttpMethod.GET, HttpEntity.newInstance(headers), Form[].class).body restTemplate.exchange( "/forms", HttpMethod.GET, HttpEntity.newInstance(headers), new ParameterizedTypeReference>() {}).body

Slide 370

Slide 370 text

Применимость FeignClient – the best если есть готовы контракт с которым есть интеграция * Но есть ньюансы RestTemplate — более общий инструмент, подойдёт в большем спектре случай, но решение будет читаться хуже и будет больше технических деталей

Slide 371

Slide 371 text

Получили Client Side LB Нахаляву!

Slide 372

Slide 372 text

Попроще никак?

Slide 373

Slide 373 text

Принципы SOA 373 1. Standardized service contract 2. Loose coupling 3. Encapsulation 4. Reusability 5. Autonomy 6. Statelessness 7. Discoverability

Slide 374

Slide 374 text

Принципы SOA 374 1. Standardized service contract 2. Loose coupling 3. Encapsulation 4. Reusability 5. Autonomy 6. Statelessness 7. Discoverability

Slide 375

Slide 375 text

Fluent annotations 375 @Getter // generate getters @Setter // generate setters @Aspect // we are an aspect @ToString // generate toString() @EnableWs // SOAP is so enterprisy, we definitely need it @Endpoint // Seriously, just read above @EnableWebMvc // we want MVC @EnableCaching // and we want to cache stuff @Configuration // this class can configure itself @RestController // we want some REST @XmlRootElement // this component is marshallable @EnableWebSocket // we want web socket, it's so new-generation @RedisHash("cat") // this class is an entity saved in redis @EnableScheduling // we want scheduled tasks @EnableWebSecurity // and some built-in security @NoArgsConstructor // generate no args constructor @ContextConfiguration // we want context configuration for unit testing @SpringBootApplication // this is a Sprint Boot application @Accessors(chain = true) // getters/setters are chained (ala jQuery) @EnableAspectJAutoProxy // we want AspectJ auto proxy @EnableAutoConfiguration // and auto configuration

Slide 376

Slide 376 text

Парадокс централизации Чтобы эффективно разрабатывать распределённые приложения, нам нужны очень хорошие централизованные библиотеки и инструменты Например: логирование, health-checking, метрики, обработка типовых ошибок, автодокументирование 376

Slide 377

Slide 377 text

Парадокс централизации Чтобы эффективно разрабатывать распределённые приложения, нам нужны очень хорошие централизованные библиотеки и инструменты Но: не выносите бизнес-логику или доменные объекты! Не размывайте бизнес-контекст вашего API 377

Slide 378

Slide 378 text

Управление конфигурацией

Slide 379

Slide 379 text

Spring Сloud Сonfig Тот, что хранит настройки

Slide 380

Slide 380 text

Что лежит внутри ● application.yml ● application-test.yml ● examinator.yml ● examinator-dev.yml

Slide 381

Slide 381 text

Your own Config Server ● Создать модуль config-server клиент implementation 'org.springframework.cloud:spring-cloud-starter-config' сервер implementation 'org.springframework.cloud:spring-cloud-config-server' @EnableConfigServer spring: cloud: config: server: git: uri: адрес репозитория

Slide 382

Slide 382 text

Your own Config Server Можно проверить конфиги по адресу: http://host:port/{label}/{application_name}-{profile}.yml или ● /{label}/{name}-{profiles}.yml ● /{name}-{profiles}.yml ● /{name}-{profiles}.yaml ● /{name}/{profile}/{label} ● ...

Slide 383

Slide 383 text

Проблема курица и яйца Откуда брать координаты eureka? ● из сonfig-server (для всех же одинаковые) ● из локальных настроек (ENV/*.yml/etc) Откуда брать координаты сonfig-server ● из eureka ● из локальных настроек (ENV/*.yml/etc)

Slide 384

Slide 384 text

App Instance #0 App Instance #N Config Server Eureka Bootstrap Server URL ИЛИ

Slide 385

Slide 385 text

App Instance #0 App Instance #N Config Server Eureka Bootstrap Server URL ИЛИ

Slide 386

Slide 386 text

Config Server Discovery Через Service Discovery App Instance #0 App Instance #N Config Server По прямой ссылке Eureka

Slide 387

Slide 387 text

Config Server Discovery Через Service Discovery App Instance #0 App Instance #N Eureka Config Server register on start get Config Server by name

Slide 388

Slide 388 text

Config Server Discovery Через Service Discovery App Instance #0 App Instance #N Eureka Config Server register on start return config server instances location get Config Server by name

Slide 389

Slide 389 text

Config Server Discovery Через Service Discovery App Instance #0 App Instance #N Eureka Config Server register on start return config server instances location get Config Server by name get configs for App

Slide 390

Slide 390 text

Config Server Discovery По прямой ссылке App Instance #0 App Instance #N Config Server get configs for App Http Load Balancer

Slide 391

Slide 391 text

Config Client ● интегрируем config-server и *-service через eureka ● включаем/отключаем management.security

Slide 392

Slide 392 text

Обновление на лету @RefreshScope

Slide 393

Slide 393 text

Начнём с примера @RestController @RefreshScope public class TestController { @Value("${foo.bar}") String test; @GetMapping("/foo") public String getFooBar() { return test; } }

Slide 394

Slide 394 text

Начнём с примера @RestController @RefreshScope public class TestController { @Value("${foo.bar}") String test; @GetMapping("/foo") public String getFooBar() { return test; } }

Slide 395

Slide 395 text

Начнём с примера @RestController @RefreshScope public class TestController { @Value("${foo.bar}") String test; @GetMapping("/foo") public String getFooBar() { return test; } }

Slide 396

Slide 396 text

Три простых шага 1. Ставим @RefreshScope над бином который нужно обновлять 2. Обновляем в config server foo.bar: some val a. Можно не править а дёрнуть /env если есть actuator 3. Дёргаем у приложения /refresh a. Для этого нужен actuator

Slide 397

Slide 397 text

А как обновить всё разом?

Slide 398

Slide 398 text

Spring Cloud Bus

Slide 399

Slide 399 text

Физика Математика Экзаминатор Экзаминатор Теология Теология Config Server ALL APP Discovery Server ALL APP

Slide 400

Slide 400 text

Физика Математика Экзаминатор Экзаминатор Теология Теология Queue Config Server ALL APP Discovery Server ALL APP ALL APP

Slide 401

Slide 401 text

Spring Cloud Bus dependencyManagement { imports { mavenBom 'org.springframework.cloud:spring-cloud-bus:2.1.1.RELEASE' } } dependencies { compile 'org.springframework.cloud:spring-cloud-starter-bus-amqp' }

Slide 402

Slide 402 text

Настройки в сonfig server application.yml spring: rabbitmq: host: localhost port: 5672

Slide 403

Slide 403 text

Теперь достаточно /refresh на config-server 1. Все приложения обновят конфигурации при получении refresh ивента в rabbitmq

Slide 404

Slide 404 text

Теперь достаточно /refresh на config-server 1. Все приложения обновят конфигу при получении refresh ивента в rabbitmq 2. Для автоматизации можно использовать config-monitor + git webhook compile 'org.springframework.cloud:spring-cloud-config-monitor' 3. Не забывать @RefreshScope

Slide 405

Slide 405 text

spring-cloud-config-monitor GitHub commit Config Monitor webhook Queue refresh event

Slide 406

Slide 406 text

spring-cloud-config-monitor Config Server Экзаминатор Экзаминатор GitHub commit Config Monitor webhook Queue refresh event Теология Теология Теология ... auto /refresh on event

Slide 407

Slide 407 text

Spring Cloud Gateway

Slide 408

Slide 408 text

Физика Математика Теология Теология Queue Экзаминатор Config Server ALL APP Discovery Server ALL APP ALL APP

Slide 409

Slide 409 text

Физика Математика Экзаминатор Экзаминатор Теология Теология Queue Config Server ALL APP Discovery Server ALL APP ALL APP

Slide 410

Slide 410 text

Физика Математика Экзаминатор Экзаминатор Теология Теология Queue Config Server ALL APP Discovery Server ALL APP ALL APP Экзаминатор

Slide 411

Slide 411 text

Экзаминатор:8080 Экзаминатор:8081 Экзаминатор:8082 Экзаминатор:32634 Экзаминатор:...

Slide 412

Slide 412 text

Физика Математика Экзаминатор Экзаминатор Теология Теология Gateway Server Queue Config Server ALL APP Discovery Server ALL APP ALL APP

Slide 413

Slide 413 text

Reverse Proxy Problem @EnableZuulProxy vs @EnableZuulServer Spring boot 1.x.x

Slide 414

Slide 414 text

Зависимости Zuul – Gateway dependencies { compile 'org.springframework.cloud:spring-cloud-starter-zuul' } Spring boot 1.x.x

Slide 415

Slide 415 text

Зависимости Spring Cloud Gateway dependencies { compile 'org.springframework.cloud:spring-cloud-starter-gateway' //for webflux compile 'org.springframework.cloud:spring-cloud-gateway-webflux' //or for mvc compile 'org.springframework.cloud:spring-cloud-gateway-mvc' } Spring boot 2.x.x

Slide 416

Slide 416 text

Зависимости Spring Cloud Gateway dependencies { compile 'org.springframework.cloud:spring-cloud-starter-gateway' //for webflux compile 'org.springframework.cloud:spring-cloud-gateway-webflux' //or for mvc compile 'org.springframework.cloud:spring-cloud-gateway-mvc' } application.yml: spring: cloud.gateway.discovery.locator.enabled: true Spring boot 2.x.x

Slide 417

Slide 417 text

Был Zuul, стал cloud gateway - зачем?

Slide 418

Slide 418 text

Почему стоит мигрировать? ● Zuul устарел и почти не поддерживается, Zuul 2 ждали долго ● Zuul не совместим с Spring Boot 2.1 ● Spring Cloud Gateway работает на Netty ● Spring Cloud Gateway имеет сильно больше фильтров “из коробки”

Slide 419

Slide 419 text

Роутинг в конфигурации zuul zuul: ignoredServices: '*' routes: student: path: /exam/** stripPrefix: true serviceId: examinator

Slide 420

Slide 420 text

Zuul.Фильтры @Component public class ChangeSearchFilter extends ZuulFilter { public String filterType() { return PRE_TYPE; } public int filterOrder() { return PRE_DECORATION_FILTER_ORDER + 1;} public boolean shouldFilter() { HttpServletRequest request = RequestContext.getCurrentContext() .getRequest(); return request.getRequestURI().startsWith( "/exam") && StringUtils.isEmpty(request.getHeader("studentId")); } ...

Slide 421

Slide 421 text

Zuul.Фильтры @Component public class ChangeSearchFilter extends ZuulFilter { ... public Object run() throws ZuulException { RequestContext ctx = RequestContext. getCurrentContext(); ctx.addZuulRequestHeader( "Request-time", Long.toString(System.currentTimeMillis())); return null; } }

Slide 422

Slide 422 text

Роутинг в конфигурации gateway spring: cloud: gateway: routes: - id: math uri: lb://math predicates: - Path=/math/**

Slide 423

Slide 423 text

Gateway.Фильтры @Bean public RouteLocator route(RouteLocatorBuilder builder) { return builder.routes() .route(r -> r.host( "**.some.org").and().path("/exam") .filters(f ->f.addResponseHeader( "Request-time", currentTime)) .uri("lb://examinator") ).build(); }

Slide 424

Slide 424 text

Gateway ● Создаем проект с gateway ● Подключаем его к service-discovery ● Пишем конфигурацию для роутинга в examinator

Slide 425

Slide 425 text

Сказка о балансировщике который не смог

Slide 426

Slide 426 text

Сказка о балансировщике который не смог External LB

Slide 427

Slide 427 text

Сказка о балансировщике который не смог External LB Local Node LB

Slide 428

Slide 428 text

Сказка о балансировщике который не смог External LB Local Node LB App Level LB

Slide 429

Slide 429 text

Сказка о балансировщике который не смог External LB Local Node LB App Level LB Zuul haproxy F5 App Type A Client Side LB App Type A Client Side LB App Type A Client Side LB

Slide 430

Slide 430 text

Сказка о балансировщике который не смог External LB Local Node LB App Level LB App Type A Client Side LB App Type A Client Side LB App Type A Client Side LB App Type B Client Side LB App Type B Client Side LB App Type B Client Side LB Zuul haproxy F5 SSL/DDOS/ Protection/BGP/Publication Data Locality/Cluster HA/ Cluster Health App Level LB/Metrics/ Advanced Routing/Auth

Slide 431

Slide 431 text

Сказка о балансировщике который не смог External LB Local Node LB App Level LB App Type A Client Side LB App Type A Client Side LB App Type A Client Side LB App Type B Client Side LB App Type B Client Side LB App Type B Client Side LB Zuul haproxy F5 SSL/DDOS/ Protection/BGP/Publication Data Locality/Cluster HA/ Cluster Health App Level LB/Metrics/ Advanced Routing/Auth

Slide 432

Slide 432 text

Сказка о балансировщике который не смог External LB Local Node LB App Level LB App Type A Client Side LB App Type A Client Side LB App Type A Client Side LB App Type B Client Side LB App Type B Client Side LB App Type B Client Side LB Zuul haproxy F5 SSL/DDOS/ Protection/BGP/Publication App Level LB/Metrics/ Advanced Routing/Auth Discovery service Discovery service Discovery service Data Locality/Cluster HA/ Cluster Health

Slide 433

Slide 433 text

Защити себя сам 433

Slide 434

Slide 434 text

434 Хочу бегемота! Rent Service Payment Service Security Service Blockchain Service Insurance Service 5мс

Slide 435

Slide 435 text

435 Хочу бегемота! Rent Service Payment Service Security Service Blockchain Service Insurance Service 300мс

Slide 436

Slide 436 text

436 Хочу бегемота! Rent Service Payment Service Security Service Blockchain Service Insurance Service 300мс

Slide 437

Slide 437 text

437 Хочу бегемота! Rent Service Payment Service Security Service Blockchain Service Insurance Service 300мс

Slide 438

Slide 438 text

438 Хочу бегемота! Rent Service Payment Service Security Service Blockchain Service Insurance Service 300мс

Slide 439

Slide 439 text

439 Circuit Breaker

Slide 440

Slide 440 text

440 Хочу бегемота! Rent Service Payment Service Security Service Blockchain Service Insurance Service 300мс

Slide 441

Slide 441 text

441 Хочу бегемота! Rent Service Payment Service Security Service Blockchain Service Insurance Service 300мс Open

Slide 442

Slide 442 text

442 Хочу бегемота! Rent Service Payment Service Security Service Blockchain Service Insurance Service 300мс Half-Open

Slide 443

Slide 443 text

443 Хочу бегемота! Rent Service Payment Service Security Service Blockchain Service Insurance Service 5мс Half-Open

Slide 444

Slide 444 text

444 Хочу бегемота! Rent Service Payment Service Security Service Blockchain Service Insurance Service 5мс

Slide 445

Slide 445 text

Уиии, хочу hystrix!!!

Slide 446

Slide 446 text

Из чего состоит Hystrix ● Механизм Circuit breaker

Slide 447

Slide 447 text

Из чего состоит Hystrix ● Механизм Circuit breaker ● Механизм Timeout

Slide 448

Slide 448 text

Из чего состоит Hystrix ● Механизм Circuit breaker ● Механизм Timeout ● Механизм BulkHead

Slide 449

Slide 449 text

Режимы работы ● Threads ● Semaphore

Slide 450

Slide 450 text

Rent Service Payment Service Security Service Blockchain Service Insurance Service threadpool size timeout x = 10 настроек

Slide 451

Slide 451 text

Rent Service Payment Service Security Service Blockchain Service Insurance Service threadpool size connection timeout read timeout timeout x = 20 настроек

Slide 452

Slide 452 text

452 Хочу бегемота! Rent Service Payment Service Security Service Blockchain Service Insurance Service Open

Slide 453

Slide 453 text

453 Хочу бегемота! Rent Service Payment Service Security Service Blockchain Service Insurance Service Open Надо подкрутить таймауты!

Slide 454

Slide 454 text

454 Хочу бегемота! Rent Service Payment Service Security Service Blockchain Service Insurance Service

Slide 455

Slide 455 text

455 Хочу бегемота! Rent Service Payment Service Security Service Blockchain Service Insurance Service Open

Slide 456

Slide 456 text

456 Хочу бегемота! Rent Service Payment Service Security Service Blockchain Service Insurance Service Open Надо подкрутить таймауты!

Slide 457

Slide 457 text

No content

Slide 458

Slide 458 text

458 Хочу бегемота! Rent Service Payment Service Security Service Blockchain Service Insurance Service Open Да блин!

Slide 459

Slide 459 text

Прохождение запроса в системе

Slide 460

Slide 460 text

А еще я жру потоки, когда не следят

Slide 461

Slide 461 text

… но проблема-то конечно не инструментах :)

Slide 462

Slide 462 text

Кто-нибудь рассчитывает timeout?

Slide 463

Slide 463 text

Может быть мониторите circuitbreaker?

Slide 464

Slide 464 text

464

Slide 465

Slide 465 text

hystrix/apache camel/akka 465

Slide 466

Slide 466 text

466 Spring boot 1.x.x

Slide 467

Slide 467 text

Hystrix устарел

Slide 468

Slide 468 text

Новичок resilience4j

Slide 469

Slide 469 text

Отличия

Slide 470

Slide 470 text

Отличия ● Более легковесный (из коробки тянет только vavr) ● Не пытается сам управлять пулом потоков

Slide 471

Slide 471 text

Отличия ● Более легковесный (из коробки тянет только vavr) ● Не пытается сам управлять пулом потоков ● Нет request collapser ● Есть rate limiter ● Есть retry

Slide 472

Slide 472 text

Отличия ● Более легковесный (из коробки тянет только vavr) ● Не пытается сам управлять пулом потоков ● Нет request collapser ● Есть rate limiter ● Есть retry ● Удобное оборачивание методов “слоями” в функциональном стиле или набором аннотаций ● Собранные “обертки” можно переиспользовать

Slide 473

Slide 473 text

Gateway ● Делаем так, чтобы один из сервисов(java,math) возращал ошибку в 50% случаев ● Подключаем hystrix и настраиваем для него cicruitbreaker на закрытие ● Пишем конфигурацию для роутинга в examinator

Slide 474

Slide 474 text

… но инструмент все еще не решит все проблемы сам :)

Slide 475

Slide 475 text

Gateway + Hystrix + Dashboard + Discovery dependencies { compile 'org.springframework.boot:spring-boot-starter-web' compile 'org.springframework.boot:spring-boot-starter-actuator' compile 'org.springframework.cloud:spring-cloud-starter-zuul' compile 'org.springframework.cloud:spring-cloud-starter-eureka' compile 'org.springframework.cloud:spring-cloud-starter-hystrix' compile 'org.springframework.cloud:spring-cloud-starter-hystrix-dashboard' } Spring boot 1.x.x

Slide 476

Slide 476 text

Следи за своим ПО 476

Slide 477

Slide 477 text

Нет трассировки - нет проблем? :) 477

Slide 478

Slide 478 text

X-Request-Id = X-Request-Id ?: new ID Простой вариант с ServletFilter 478

Slide 479

Slide 479 text

spring-cloud-sleuth/open zipkin 479

Slide 480

Slide 480 text

480 Rent Service No TraceId No SpanId TraceId = X SpanId = A

Slide 481

Slide 481 text

481 Rent Service Payment Service No TraceId No SpanId TraceId = X SpanId = A TraceId = X SpanId = B TraceId = X SpanId = C

Slide 482

Slide 482 text

482 Rent Service Payment Service Blockchain Service No TraceId No SpanId TraceId = X SpanId = A TraceId = X SpanId = B TraceId = X SpanId = C TraceId = X SpanId = D TraceId = X SpanId = D TraceId = X SpanId = F

Slide 483

Slide 483 text

483 Rent Service Payment Service Security Service Blockchain Service No TraceId No SpanId TraceId = X SpanId = A TraceId = X SpanId = B TraceId = X SpanId = C TraceId = X SpanId = D TraceId = X SpanId = D TraceId = X SpanId = E TraceId = X SpanId = E TraceId = X SpanId = F TraceId = X SpanId = G

Slide 484

Slide 484 text

484 Rent Service Payment Service Security Service Blockchain Service No TraceId No SpanId TraceId = X SpanId = A TraceId = X SpanId = B TraceId = X SpanId = B TraceId = X SpanId = C TraceId = X SpanId = C TraceId = X SpanId = D TraceId = X SpanId = D TraceId = X SpanId = E TraceId = X SpanId = E TraceId = X SpanId = F TraceId = X SpanId = G

Slide 485

Slide 485 text

485 Rent Service Payment Service Security Service Blockchain Service TraceId = X SpanId = A No TraceId No SpanId TraceId = X SpanId = A TraceId = X SpanId = A TraceId = X SpanId = B TraceId = X SpanId = B TraceId = X SpanId = C TraceId = X SpanId = C TraceId = X SpanId = D TraceId = X SpanId = D TraceId = X SpanId = E TraceId = X SpanId = E TraceId = X SpanId = F TraceId = X SpanId = G

Slide 486

Slide 486 text

486

Slide 487

Slide 487 text

487

Slide 488

Slide 488 text

488 Rent Service Payment Service

Slide 489

Slide 489 text

489 Rent Service Payment Service SpanId = B Client Send TraceId = X SpanId = A

Slide 490

Slide 490 text

490 Rent Service Payment Service SpanId = B Client Send SpanId = B Server Received TraceId = X SpanId = A TraceId = X SpanId = C

Slide 491

Slide 491 text

491 Rent Service Payment Service SpanId = B Client Send SpanId = B Server Received SpanId = B Server Send TraceId = X SpanId = A TraceId = X SpanId = C

Slide 492

Slide 492 text

492 Rent Service Payment Service SpanId = B Client Send SpanId = B Server Received SpanId = B Client Received SpanId = B Server Send TraceId = X SpanId = A TraceId = X SpanId = C

Slide 493

Slide 493 text

documentation → smart documentation 493

Slide 494

Slide 494 text

Not smart = This is main documentation This document describes how to be the most fundamental and important document in the world of documents ... COPY-PASTE documentation from another document ... 494

Slide 495

Slide 495 text

Not so smart = This is main documentation This document describes how to be the most fundamental and important document in the world of documents include::https://raw.github.com/asciidoctor/asciidoctor/master/Gemfile[] include::../other.adoc[] include::/home/tolkv/git/docs-0/superdoc.adoc[] 495

Slide 496

Slide 496 text

Really smart = This is main documentation This document describes how to be the most fundamental and important document in the world of documents include::https://raw.github.com/asciidoctor/asciidoctor/master/Gemfile[] include::gradle://gradle-advanced:service-with-deps:1.0/deps.adoc[] include::gradle://:service/doc.adoc[] 496

Slide 497

Slide 497 text

Payment Service[jar,doc] Insurance Service [jar,doc] One Point of View [UberDoc.zip] Rent Service[jar,doc] Other Service [jar,doc] Агрегация информации 497

Slide 498

Slide 498 text

Парадокс централизации Чтобы эффективно разрабатывать распределённые приложения, нам нужны очень хорошие централизованные библиотеки и инструменты Например: логирование, health-checking, метрики, обработка типовых ошибок, автодокументирование 498

Slide 499

Slide 499 text

Парадокс централизации Чтобы эффективно разрабатывать распределённые приложения, нам нужны очень хорошие централизованные библиотеки и инструменты Но: не выносите бизнес-логику или доменные объекты! Не размывайте бизнес-контекст вашего API 499

Slide 500

Slide 500 text

Пришло время поговорить про Reactive

Slide 501

Slide 501 text

Зачем мне туда лезть?

Slide 502

Slide 502 text

Реактивные микросервисы!

Slide 503

Slide 503 text

Reactive manifesto Отзывчивость Эластичность Стабильность Асинхронное адресное общение * * у сообщения есть адресат * топология системы динамическая * компоненты слабо связаны

Slide 504

Slide 504 text

И как это сделать?

Slide 505

Slide 505 text

Ну тут условий много...

Slide 506

Slide 506 text

Reactive manifesto Отзывчивость Эластичность Стабильность Асинхронное адресное общение * * у сообщения есть адресат * топология системы динамическая * компоненты слабо связаны

Slide 507

Slide 507 text

Изоляция сбоев и selfhealing...

Slide 508

Slide 508 text

Reactive manifesto Отзывчивость Эластичность Стабильность Асинхронное адресное общение * * у сообщения есть адресат * топология системы динамическая * компоненты слабо связаны

Slide 509

Slide 509 text

Слабая связность...

Slide 510

Slide 510 text

Reactive manifesto Отзывчивость Эластичность Стабильность Асинхронное адресное общение * * у сообщения есть адресат * топология системы динамическая * компоненты слабо связаны

Slide 511

Slide 511 text

Стримминг на всех уровнях

Slide 512

Slide 512 text

Reactive manifesto Отзывчивость Эластичность Стабильность Асинхронное адресное общение * * у сообщения есть адресат * топология системы динамическая * компоненты слабо связаны

Slide 513

Slide 513 text

NIO и MQ

Slide 514

Slide 514 text

514 Хочу бегемота! Rent Service Payment Service Security Service Blockchain Service Insurance Service

Slide 515

Slide 515 text

515 Хочу бегемота! Rent Service Payment Service Security Service Blockchain Service Insurance Service Sync Sync Sync

Slide 516

Slide 516 text

Controller Service HttpClient DBClient

Slide 517

Slide 517 text

Controller Service HttpClient DBClient

Slide 518

Slide 518 text

Controller Service HttpClient DBClient

Slide 519

Slide 519 text

Controller Service HttpClient DBClient

Slide 520

Slide 520 text

Частичная асинхронность тут не поможет...

Slide 521

Slide 521 text

Реактивные стримы!

Slide 522

Slide 522 text

Не могу больше пить. Давайте смотреть

Slide 523

Slide 523 text

Publisher Subscriber подписка данные Реактивные стримы

Slide 524

Slide 524 text

Publisher Publisher/ Subscriber подписка данные Реактивные стримы Subscriber подписка данные

Slide 525

Slide 525 text

Publisher Publisher/ Subscriber подписка данные Реактивные стримы Subscriber подписка данные

Slide 526

Slide 526 text

Publisher Publisher/ Subscriber Реактивные стримы Subscriber Управляющие сигналы

Slide 527

Slide 527 text

Publisher Publisher/ Subscriber Реактивные стримы Subscriber Subscribe Cancel Request

Slide 528

Slide 528 text

Publisher Publisher/ Subscriber Реактивные стримы Subscriber данные

Slide 529

Slide 529 text

Publisher Publisher/ Subscriber Реактивные стримы Subscriber Next Complete Error

Slide 530

Slide 530 text

Publisher Publisher/ Subscriber Реактивные стримы Subscriber Next Complete Error

Slide 531

Slide 531 text

И как вот это все встраивается в приложение?

Slide 532

Slide 532 text

Netty. Асинхронный вход Client Client Client Async threads Event loop Single thread Selector Delegate

Slide 533

Slide 533 text

Reactor IPC Netty Controllers Spring WebFlux WebFlux

Slide 534

Slide 534 text

Reactor IPC Netty Dispatcher Handler Controllers Channel Operations Spring WebFlux WebFlux

Slide 535

Slide 535 text

Reactor IPC Netty WebFlux Dispatcher Handler Controllers Channel Operations Publisher Spring WebFlux

Slide 536

Slide 536 text

Reactor IPC Netty WebFlux Dispatcher Handler Controllers Channel Operations Publisher Publisher Spring WebFlux

Slide 537

Slide 537 text

Reactor IPC Netty WebFlux Dispatcher Handler Controllers Channel Operations Publisher Publisher Spring WebFlux

Slide 538

Slide 538 text

Ну это на входе, А с другого конца?

Slide 539

Slide 539 text

Асинхронный клиент Reactor IPC Netty ... WebClient

Slide 540

Slide 540 text

Асинхронный клиент Netty ... WebClient Netty ... Controller App logic

Slide 541

Slide 541 text

Асинхронный клиент Netty ... WebClient Netty ... Controller App logic

Slide 542

Slide 542 text

Config Client ● Пробуем сделать examinator реактивным ● Подключаем spring-boot-starter-webflux ● Возвращаем из контроллера Mono ● Заменяем RestTemplate на WebClient ● Выстраиваем стрим от клиента до контроллера

Slide 543

Slide 543 text

No content

Slide 544

Slide 544 text

Для чего RPC Чтобы жизнь была легкой

Slide 545

Slide 545 text

gRPC это счастье это радость это будущее в каждый дом

Slide 546

Slide 546 text

Да ладно, и нет минусов?

Slide 547

Slide 547 text

Давайте посмотрим

Slide 548

Slide 548 text

1. Сборка

Slide 549

Slide 549 text

Gradle apply plugin: "com.google.protobuf" ...

Slide 550

Slide 550 text

Gradle apply plugin: "com.google.protobuf" protobuf { protoc { artifact = 'com.google.protobuf:protoc' } generatedFilesBaseDir = "$projectDir/generated" plugins { grpc { artifact = 'io.grpc:protoc-gen-grpc-java' } reactor { artifact = "com.salesforce.servicelibs:reactor-grpc:0.9.0:jdk8@jar" } } generateProtoTasks { ofSourceSet('main')*.plugins { grpc { } reactor { } }

Slide 551

Slide 551 text

reactor { artifact = "com.salesforce.servicelibs:reactor-grpc:0.9.0:jdk8@jar" } } generateProtoTasks { ofSourceSet('main')*.plugins { grpc { } reactor { } } } } clean { delete protobuf.generatedFilesBaseDir } idea { module { generatedSourceDirs += file("${protobuf.generatedFilesBaseDir}/main/java") generatedSourceDirs += file("${protobuf.generatedFilesBaseDir}/main/reactor") generatedSourceDirs += file("${protobuf.generatedFilesBaseDir}/main/grpc") generatedSourceDirs += file("${protobuf.generatedFilesBaseDir}/main/rsocketRpc") } } dependencies { compile 'com.google.protobuf:protobuf-java' Gradle

Slide 552

Slide 552 text

ofSourceSet('main')*.plugins { grpc { } reactor { } } } } clean { delete protobuf.generatedFilesBaseDir } idea { module { generatedSourceDirs += file("${protobuf.generatedFilesBaseDir}/main/java") generatedSourceDirs += file("${protobuf.generatedFilesBaseDir}/main/reactor") generatedSourceDirs += file("${protobuf.generatedFilesBaseDir}/main/grpc") generatedSourceDirs += file("${protobuf.generatedFilesBaseDir}/main/rsocketRpc") } } dependencies { compile 'com.google.protobuf:protobuf-java' compile 'io.grpc:grpc-stub' compile 'io.grpc:grpc-protobuf' compile 'com.salesforce.servicelibs:reactor-grpc-stub' } Gradle

Slide 553

Slide 553 text

2. Описание

Slide 554

Slide 554 text

*.proto import "google/api/annotations.proto"; package my.error_service; service Errors { rpc GetErrorClass (GetErrorClassRequest) returns (GetErrorClassResponse) { option (google.api.http) = { post: "/errorclass" body: "*" }; } } message GetErrorClassRequest { string error_id = 1; } message GetErrorClassResponse { string error_class = 1; }

Slide 555

Slide 555 text

Почему это не сделали в плагине?

Slide 556

Slide 556 text

No content

Slide 557

Slide 557 text

No content