Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Alfa Microservices, Spring Boot and Spring Cloud

Alfa Microservices, Spring Boot and Spring Cloud

About architecture, spring boot and spring cloud ecosystem

40951719c6ca509831d5c38b764661c9?s=128

Kirill Tolkachev

April 28, 2019
Tweet

Transcript

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

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

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

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

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

  6. CORBA

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

  8. CORBA. Плюсы • Независимость от конкретного языка или технологии (не

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

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

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

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

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

  14. Проблема надежности канал связи • Отказ от кастомных протоколов и

    переход на HTTP • Переход на платформонезависимые языки спецификации сообщений (json, xml)
  15. Проблема локальности обращений • Отказ от слоя абстракции скрывающего процесс

    получения данных - удаленные вызовы стали явными, разработчики стали следить за количеством удаленных вызовов
  16. Проблема сложной спецификации • CORBA умер, SOAP учел его ошибки

    • ...но не до конца, REST был проще и почти закопал SOAP • ...продолжение следует
  17. Родился SOA

  18. SOA Service 3 Service 1 Service 2 HTTP JSON XML

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

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

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

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

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

    мониторинга
  24. Наплодили сервисов Поддержка

  25. SOA

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

  27. Ситуация

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

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

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

  31. Шина

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

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

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

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

    простой и надёжный канал связи • Оптимизированный обмен сообщениями. • Стабильная спецификация обмена сообщениями. • Асинхронность обмена сообщениями и управление нагрузкой на систему. • Единая точка для управления версионированием и преобразованием форматов
  36. Да ладно, и нет минусов?

  37. Шина. Минусы • Ниже скорость связи, особенно между уже совместимыми

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

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

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

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

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

  43. None
  44. Но вернемся к микросервисам

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

  46. Попробуем отгадать • Простота масштабирования • Удобство параллельной разработки несколькими

    командами • Переиспользование в разных продуктах • ???
  47. А как вообще создавать эти ваши микросервисы?

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

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

  50. DOMAIN Driven Design

  51. DOMAIN Driven Design • Bounded context X X

  52. DOMAIN Driven Design • Continuous integration Контракт

  53. • Context map DOMAIN Driven Design

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

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

  56. DOMAIN Driven Design • ООП • Rich model • Active

    records
  57. DOMAIN Driven Design Entity Logic

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

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

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

  61. DaDD. Плюсы • Немного проще писать тесты • Меньше шансов

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

    написание монстр- логики • Уход от ООП (?)
  63. Мы готовы писать микросервисы

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    Ratpack • Micronaut • Spark • spring-fu • etc.
  82. Что у нас на сегодня? • Spring...Boot, как он работает

    и как использовать его на полную • Начнем смотреть Spring cloud из чего состоит какой он был и как изменился
  83. Spring {Boot,Cloud} Workshop

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

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

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

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

  88. 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
  89. web.xml <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <filter> <filter-name>springSecurityFilterChain</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> </filter> <filter-mapping> <filter-name>springSecurityFilterChain</filter-name>

    <url-pattern>/*</url-pattern> </filter-mapping> <servlet> <servlet-name>mvc-dispatcher</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>mvc-dispatcher</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping>
  90. None
  91. None
  92. … <context-param> <param-name>contextClass</ param-name> <param-value>…AnnotationConfigWebApplicationContext</ param-value> </context-param> <context-param> <param-name>contextConfigLocation</ param-name>

    <param-value>com.inwhite.conf.AppConfig</ param-value> </context-param> …
  93. Deployment →Use maven/gradle to build a war from that project

    →Copy it to webapps directory of tomcat
  94. 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
  95. Теперь давайте замочим XML

  96. Жизнь без web.xml <failOnMissingWebXml>false</failOnMissingWebXml> Java Servlet Specification 3.+ Tomcat 7+

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

  98. WebApplicationInitializer

  99. ServletContainerInitializer

  100. WebApplicationInitializer

  101. ServletContainerInitializer

  102. None
  103. § 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.+
  104. Как? SPI tomcat |→ get javax.servlet.ServletContainerInitializer impl via SPI

  105. § 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.+
  106. Как? SPI tomcat |→ get javax.servlet.ServletContainerInitializer impl via SPI |→

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

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

    get all WebApplicationInitializer classes (from @HandlesTypes) |→ call ServletContainerInitializer.onStartup(classes,servletCtx) according to @Order order
  109. SPI org.springframework.web.SpringServletContainerInitializer content

  110. § Class ServiceLoader<S> loader = ServiceLoader.load(ServletContainerInitializer.class) 6.+

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

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

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

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

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

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

    onStartup(Set<Class<?>> webAppInitializerClasses, ServletContext servletContext) ... AnnotationAwareOrderComparator.sort(initializers); ... initializers.forEach(initializer -> initializer.onStartup(ctx)); }
  117. Дружок, дай ка мне ServletContainerInitializer tomcat 7 Spring Jar

  118. Spring ServletContainer Initializer tomcat 7 Spring Jar

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

  120. WebApplicationInitializer W AI WAI tomcat 7 JARS

  121. W AI WAI SpringServletContainerInitializer tomcat 7

  122. 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("/*"); }
  123. А попроще нельзя?

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

  125. Как выглядит наш pom.xml <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.4.RELEASE</version> </parent>

  126. <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.4.RELEASE</version> </parent> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>2.1.4.RELEASE</version> </parent>

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

  129. Это чужой parent!

  130. None
  131. <dependencyManagement> <dependencies> <dependency> <groupId>io.spring.platform</groupId> <artifactId>platform-bom</artifactId> <version>Brussels-SR2</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies>

    </dependencyManagement>
  132. Как выглядит наш build.gradle plugins { id "org.springframework.boot" version "2.1.4.RELEASE"

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

    } dependencies { compile 'org.springframework.boot:spring-boot-starter-web' } Добавляем зависимости
  134. Как выглядит наш 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
  135. Как выглядит наш 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' } }
  136. А я не понял

  137. Web Starter ТАЩИТ!

  138. Кто всё пакует <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins>

    </build>
  139. Jar как Jar, но если зайти внутрь...

  140. None
  141. Анатомия SpringBoot Jar jar |- META-INF |- BOOT-INF |- libs

    |- classes |- org |- springframework |- boot
  142. java -jar myapp.jar myapp.jar |- META-INF |- BOOT-INF |- libs

    |- classes |- org |- springframework |- boot MANIFEST.MF ... Main-Class: ??? ...
  143. Перед запуском main – сформируй classpath

  144. JarLauncher

  145. Анатомия 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/ ...
  146. 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/ ...
  147. 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
  148. А кто прописывает манифест этому джару?

  149. <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <mainClass>conference...OurMainClass</mainClass> </configuration> </plugin> </plugins>

    </build> MANIFEST.MF ... Start-Class: conference.spring.boot.ripper.OurMainClass ...
  150. Как выбирается mainClass если его не указать Spring boot plugin

    сканирует проект – ищет мейны • если есть только один – то это он :) • если больше одного – смотрит где стоит @SpringBootApplication и выбирает его • если @SpringBootApplication нет или >1 – ошибка о множественных main при сборке
  151. Жмя и Работает executable jar для бабушки java -jar слишком

    сложно
  152. Хочу executable jar: Maven <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration>

    <executable>true</executable> </configuration> </plugin> </plugins> </build> springBoot { executable = true } Gradle bootJar { launchScript() } Spring boot 1.x.x Spring boot 2.x.x
  153. Demo. Executable jar

  154. Внутренний мир executable Jar • Бабушка хочет чтобы жмя и

    работало • windows “click click” • $ ./app.jar • ...
  155. Demo. jar structure

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

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

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

    archive Начало файла Начало zip архива
  159. Где контекс? @SpringBootApplilcation class App { public static void main(String[]

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

    args) { ApplicationContext context = SpringApplication.run(App.class,args); } }
  161. Разрешите представиться

  162. Давайте поговорим о контексте Малыш знает про ClassPathXmlApplicationContext А какие

    контексты знаешь ТЫ?
  163. Типы ConfigurableApplicationContext

  164. Это я решаю какой контекст создать Я до создания контекста

    ещё много всего делаю, но об этом потом. SpringApplication
  165. Web Context Generic Context

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

  167. Web Context Generic Context

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

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

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

  171. Откуда 436 spring beans?

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

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

  174. Задание 1. Печатать предупреждение при вызове @Deprecated 2. Печатать время

    исполнения методов @Benchmark 3. * Отправить email на адрес alarm.email если вызвали @Deprecated или @Benchmark
  175. AOP • Joint Point • Pontcut • Advise • Aspect

  176. Pointcut • execution • within • this • target •

    args • bean • @annotation
  177. Пример @Aspect @Component public class TestAspect { @Pointcut("execution(* *.doSomething(..)) &&

    args(list,..) ") public void callMethod(List<String> list) { ... } }
  178. Что за 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).
  179. Даёшь инверсию контроля для стартеров

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

  181. @SpringBootApplication

  182. @SpringBootApplication → @ComponentScan → @Configuration → @EnableAutoConfiguration

  183. @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 { …
  184. @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 { …
  185. @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 {}; }
  186. @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 {}; }
  187. @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
  188. @EnableAutoConfiguration ImportSelector Web Starter Boot Starter … Starter Mongo Starter

  189. Spring Factories Loader Jar/Starter spring.factories SpringFactoriesLoader

  190. SpringFactoriesLoader static <T> List<T> loadFactories( Class<T> factoryClass, ClassLoader cl )

    static List<String> loadFactoryNames( Class<?> factoryClass, ClassLoader cl )
  191. Даёшь инверсию контроля для стартеров

  192. 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 ….

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

  194. CacheConfigurations private static final Map<CacheType, Class<?>> MAPPINGS; static { Map<CacheType,

    Class<?>> mappings = new HashMap<CacheType, Class<?>>(); 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); }
  195. Где то внутри CacheAutoConfiguration for (int i = 0; i

    < types.length; i++) { Imports[i] = CacheConfigurations.getConfigurationClass(types[i]); } return imports;
  196. Захардкодили

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

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

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

  200. @ConditionalOn***

  201. Conditional и друзья @ConditionalOnBean @ConditionalOnClass @ConditionalOnCloudPlatform @ConditionalOnExpression @ConditionalOnJava @ConditionalOnJndi @ConditionalOnMissingBean

    @ConditionalOnMissingClass @ConditionalOnNotWebApplication @ConditionalOnProperty @ConditionalOnResource @ConditionalOnSingleCandidate @ConditionalOnWebApplication ...
  202. Паззлер @Configuration @ConditionalOnWinterIsHere public class UndeadArmyConfiguration { @Bean public WinterUndeadArmy

    cursedArmy() { return new WinterUndeadArmy(); } @Bean @ConditionalOnWinterIsHere public DragonGlassFactory dragonGlassFactory() { return new DragonGlassFactory(); }
  203. ConditionalOnPuzzler @Configuration public class КонфигурацияКазни { @Bean @ConditionalOnClass ({Мыло.class, Веревка.class})

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

    @ConditionalOnMissingBean ({ФабрикаКазни. class}) public ФабрикаКазни виселицы() { return new ФабрикаВиселиц( "..."); } @Bean @ConditionalOnClass ({Стул.class, Ток.class}) @ConditionalOnMissingBean ({ФабрикаКазни. class}) public ФабрикаКазни cтулья() { return new ФабрикаЭлектрическихСтульев( "вж вж"); } }
  205. 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 ФабрикаГильотин( "хрусть хрусть"); } }
  206. 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. Будет отлично работать
  207. 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. Будет отлично работать
  208. Потому что ASM

  209. 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; } Что если нужно изменить?
  210. Люблю Spring Boot Но хочу Tomcat

  211. 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("/*"); }
  212. 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("/*"); }
  213. public class WebStarter implements WebApplicationInitializer { @Override public void onStartup(ServletContext

    servletContext){ SpringApplication.run(RipperApplication.class); } }
  214. 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); } }
  215. А в Tomcat не запустилось! В Tomcat`e не пашет

  216. public class WebStarter implements WebApplicationInitializer{ @Override public void onStartup(ServletContext servletContext)

    throws ServletException { SpringApplication.run(RipperApplication.class); } } Tomcat в Tomcat`е
  217. Читаем документацию

  218. § 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); } }
  219. § 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); } }
  220. § 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); } } Работает по разному
  221. § 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); } }
  222. § 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
  223. § 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 плагины Обязательно
  224. § 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); } } Опционально
  225. § 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 контейнере Опционально
  226. Анатомия War .war |- META-INF |- WEB-INF |- lib |-

    classes |- org/springframework/boot/loader |- WarLauncher and friends
  227. А как убрать 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.
  228. Анатомия War .war |- META-INF |- WEB-INF |- lib |-

    lib-provided |- classes |- org/springframework/boot/loader |- WarLauncher and friends
  229. Анатомия 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
  230. Jar стал похож на War

  231. None
  232. Замочили web.xml

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

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

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

  236. @RestController("/examine") Это имя spring bean, не http path И это

    даже может работать: • Если нет ни одного контроллера с путём (всегда будет вызываться) • Если потом указали полный путь в @RequestMapping
  237. @RequestMapping и его братья Управляет маршрутизацией запросов в метод контроллера.

    Маршрутизирует по: • name/value – сам http path • method – http method • params • headers
  238. @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() { }
  239. @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() { }
  240. @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() { }
  241. @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) { }
  242. @RequestMapping автовпрыскивание @PostMapping("/examine") public CheckedExam ex6(HttpServletRequest httpServletRequest, Authentication auth, UserDetails

    user, etc ) { }
  243. 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
  244. Наконец то будем писать код!

  245. Задание 0 Напишем стартер DoD: 1. Все контроллеры помеченые @FrontendController

    аннотацией должны обворачивать возвращаемый результат в дополнительный Json { "result": { оригинальный_json } } 2. https://github.com/lavcraft/spring-boot-and-cloud-ripper-2019 3.
  246. Talk is cheap. Show me the code Linus Torvalds https://github.com/lavcraft/spring-boot-and-cloud-ripper-2019

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

    ExaminatorApplication.class, args); }
  248. { "География":5, "Физика" :3 } Физика Математика Теология Не грешно

    ли лезть в атом? Теорема Пифагора Неравенство Коши E=? Количество вопросов Количество вопросов Экзаминатор
  249. С чего начинают строить микросервис →Контроллеры →Сервисы →Dao →Model

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

    поскольку модель используется на всех слоях, пожалуй лучше начинать с неё
  251. 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": "петух" }] }] }
  252. Data model - задание 1.1* Придумайте архитектуру модели, которая позволит

    написать Сервис: - принимающий на вход объект SolvedExam - отдающий CheckedExam с оценкой - Должны проходить тесты @Test public void checkExamineContract() throws Exception { ... mockMvc.perform(post("/examine")) ... } Use @RestController and @RequestMapping > @*Mapping Luke
  253. 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
  254. Зло наследования

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

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

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

  258. Lombok – composition / delegate and friends Annotation Processor Работает

    на этапе компиляции Генерит код, чтобы мы не писали Делает джаву более похожим на нормальный язык
  259. Про lombok, модели и не только @Data – POJO (@Getter,

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

    @Setter, @ToString, @EqualsAndHashcode) @Value – immutable POJO @AllArgumentConstruct(onConstructor = @_(@Autowired)) @RequireArgumentConstructor /@NoArgumentConstructor @Builder / @Singular @Delegate – примерно как в груви @SneakyThrows @Slf4j / @Log4j / …
  261. Теперь давайте разбираться Джэксоном

  262. Как Джексон пишет в джейсон 1. Использует Java Getters a.

    Методы начинающиеся с Get 2. @JsonIgnore – игнорируем Getter 3. Нет ни одного Getter – падает
  263. Как Джексон пишет в объект 1. Нет конструктора с @ConstructProperies

    → выставляет через Setters → если нет Setter и есть Getter – выставляет напрямую в филды → это все только при наличии пустого конструктора 2. Есть конструктор с @ConstructProperies → выставляет значение через него 3. После зачем то вызовет все геттеры * Но если есть то @JsonIgnore всё по другому * Это поведение по умолчанию
  264. Меняем дефолтное поведение @JsonIgnoreProperties @JsonIgnoreType @JsonIgnore @JsonProperty

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

  266. → Если вы настраиваете руками: 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
  267. Достаточно одних зависимостей Если вы работаете с Spring Boot 1.x.x

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

    2.x.x
  269. Как Spring MVC работает с Джексоном Напишите метод который принимает

    json и класс, а возвращает объект данного класса Пробуем использовать objectMapper Jackson2
  270. @DateTimeFormat Ну вы в курсе… А ещё можно в application.properties

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

  272. Кто использует Jackson в мире Spring MVC 1. ClassLoader 2.

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

    Dispatcher Servlet 3. Tomcat 4. BeanPostProcessor
  274. Задание 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
  275. { "География":5, "Физика" :3 } Физика Математика Теология Не грешно

    ли лезть в атом? Теорема Пифагора Неравенство Коши ваы Количество вопросов Количество вопросов Экзаминатор Person p = restTemplate.getForObject("/{name}/details", Person.class, name); Для связи сервисов используем RestTemplate
  276. Конфликт портов — 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}}'
  277. 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": "петух" }] }] }
  278. compile 'org.springframework.data:spring-data-rest-webmvc' Подключаем Spring Data Rest

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

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

  281. Дальше пишем 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
  282. Как поменять стратегию @Component public class MyWebConfiguration extends RepositoryRestConfigurerAdapter {

    @Override public void configureRepositoryRestConfiguration( RepositoryRestConfiguration config) { config.setRepositoryDetectionStrategy( ALL); } }
  283. Как задать URL @Configuration class CustomRestMvcConfiguration { @Bean public RepositoryRestConfigurer

    repositoryRestConfigurer() { return new RepositoryRestConfigurerAdapter() { @Override public void configureRepositoryRestConfiguration( RepositoryRestConfiguration config) { configuration.setBasePath( "/api") } }; } }
  284. Как задать 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
  285. Spring Data Rest official supports →Spring Data JPA →Spring Data

    MongoDB →Spring Data Neo4j →Spring Data GemFire →Spring Data Cassandra
  286. @RepositoryRestResource @RepositoryRestResource (collectionResourceRel = "people", path = "people") public interface

    PersonRepository extends MongoRepository<Person, String> { @RestResource(path = "byname") List<Person> findByLastName(@Param( "name") String name); }
  287. 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
  288. { "География":5, "Физика" :3 } Физика Математика Теология Не грешно

    ли лезть в атом? Теорема Пифагора Неравенство Коши ваы Количество вопросов Количество вопросов Экзаминатор
  289. Задание 3 Связать сервисы Экзаменатора и Предметы • Запустить и

    проверить самим • Должен отдаваться запрос с ответами другого сервиса { "География":5, "Физика" :3 }
  290. --server.port Конфликт портов решается с помощью relaxed properties export SERVER_PORT=8081

    java -jar --server.port=8081 SPRING_APPLICATION_JSON = '{"server":{"port":8081}}'
  291. 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);
  292. Шаринг кода модель/бизнес логика/инфраструктурный код • Шарить • Или не

    шарить
  293. Подход №1 - общий код Зачем разбивать микросервис на модули?

    → Java API для сервисов → фиксация контракта на уровне зависимостей языка → утилитарная функция, избавления от бойлерплейта
  294. Подход №1 - общий код project |- project-sdk |- project-app

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

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

    |- project-api |- project-domain |- project-... Пфф KISS
  297. Подход №2 - общий контракт → разделение кода и контракта

    → поставка контракта отдельно
  298. Обратимся к истории → REST подход ◦ → RPC подход

  299. Обратимся к истории → REST подход ◦ анархия и рекомендации

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

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

    → RPC подход ◦ jax-ws/jax-rpc ◦ corba ◦ json rpc ◦ thrift ◦ protobuf/grpc ◦ etc
  302. Задание 5 • пишем SDK для вызова микросервиса по теологии

    • и тесты для него • тестируем контракт • тестируем взаимодействие ◦ WireMock/Spring MockServer ◦ Spring Boot Test ◦ Context Scanning behaviour Тест SDK Тест Контракта Тест Взаимодействия
  303. Разбиваем микросервис на модули Кому отсыпать наносервисов?

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

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

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

  307. { "География":5, "Физика" :3 } Физика Математика Теология Не грешно

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

    Неравенство Коши ваы Количество вопросов Количество вопросов Экзаминатор Бог Не грешно ли лезть в атом?
  309. Матмематика – сервис • Сделать новый модуль • Реализовать метод

    "/exercise/random" • Возвращать список автогенерируемых упражнение (как в Теологии)
  310. Как воткнуть в Examinator?

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

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

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

    "math" : "http://localhost:8082/" "examinator": "http://localhost:8081/" "..." : "http://localhost:8083/" Service Registry в application.yml
  314. А как шарить service registry в yml?

  315. Service Registry

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

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

    вопросов Экзаминатор Экзаминатор Теология Service Registry Clients Server
  318. Service Registry

  319. Что хранится в Service Registry? • serviceId • Ip адрес

    и порт • Данные о хелсчеках • Метаданные ◦ Данные о геозонах ◦ Пользовательские данные
  320. Кстати о хелсчеках Service Service registry Heartbeat

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

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

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

  324. /actuator/health { "status": "UP", "details": { "diskSpace": { "status": "UP",

    "details": { "total": 499963174912, "free": 354837377024, "threshold": 10485760 } }, "refreshScope": { "status": "UP" }, ….
  325. Можно конечно и хелсчек eureka: client: healthcheck: enabled: true

  326. Service Eureka Marathon Marathon Lb

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

  328. 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
  329. Собственный 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
  330. Переводим на 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'
  331. Переводим на 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'
  332. Переводим на 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
  333. @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
  334. @EnableEurekaServer Будет включен по умолчанию при добавлении стартера c Edgware

    spring-cloud release train application.yml: server.port: 8761 spring.application.name: registry eureka: client.register-with-eureka= false
  335. @EnableEurekaServer open http://localhost:8761

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

    open close?
  337. Кто это у нас там спрятался? Смотрим какие сервисы загрузились

    $ http :8082/health { "description": "Remote status from Eureka server", "status": "DOWN" } { "description": "Spring Cloud Eureka Discovery Client", "status": "UP" } Spring Boot 1.x.x
  338. Кто это у нас там спрятался? Выключаем security для управляющий

    API management: security: enabled: false Теперь $ http :8082/health Spring Boot 1.x.x
  339. { "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
  340. Кто это у нас там спрятался? application.yml management: endpoints: web:

    exposure: include: '*' Spring Boot 2.x.x
  341. Кто это у нас там спрятался? Смотрим какие сервисы загрузились

    $ http :8082/actuator/health { "status": "UP" } $ http :8082/actuator/metrics ... $ http :8082/actuator ... Spring Boot 2.x.x
  342. Как обратиться к сервисам по имени? restTemplate.getForObject( "http://"+serviceName+"/exercice/random?count=" + number,

    Exercice[].class );
  343. True Discovery • Написать контроллер, который возвращает все зарегистрированные сервисы

    • Запустить несколько сервисов одного типа, посмотреть результат @Autowired private DiscoveryClient discoveryClient; discoveryClient.getServices() discoveryClient.getInstances("theology")
  344. True Discovery • Включить логику резолва сервиса в адресе запроса

    Use @LoadBalanced or LoadBalancerInterceptor Luke
  345. Health checks starting

  346. Health checks http available starting

  347. Health checks app available http available starting

  348. Health checks marathon window app available http available starting

  349. Health checks unavailable window marathon window app available http available

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

    started available window starting working
  351. Self preservation

  352. Self preservation Service Registry 2 Service A Instance 1 Service

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

    B Instance 1 Service A Instance 2 Service B Instance 2 Service Registry 1
  354. Self preservation eureka: server.enable-self-preservation: false

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

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

    Server Side vs Client Side
  357. 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
  358. 358 Service Client Service Registry Service Instance 1 Service Instance

    N Service Instance ... Load balance request Router/Proxy Server side discovery
  359. сервис ошибки задержки сети балансировка конфигурация инфраструктура

  360. Резюмируем Discovery

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

    порты App in Docker Во вне
  362. @EnableEurekaServer open http://localhost:8761 HTTP_ADVERTIZED_PORT

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

  364. Feign Client с обратной стороны стороны @RestController @RequestMapping(value = "/v0/forms/latestByUserId")

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

    class FormsController { @GetMapping Form get(@RequestHeader("x-userid") String userId) { return new Form(..) } }
  366. Feign Client @FeignClient( name = "myApplicationName", url = "${config.myApplicationName}") @RequestMapping(value

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

    = "/v0/forms/latestByUserId") public interface FormsClient { @GetMapping Form get(@RequestHeader("x-userid") String userId); }
  368. Блеск и нищета RestTemplate restTemplate.exchange( "/cik", HttpMethod.GET, HttpEntity.newInstance(headers), Form[].class).body

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

    "/forms", HttpMethod.GET, HttpEntity.newInstance(headers), new ParameterizedTypeReference<List<Form>>() {}).body
  370. Применимость FeignClient – the best если есть готовы контракт с

    которым есть интеграция * Но есть ньюансы RestTemplate — более общий инструмент, подойдёт в большем спектре случай, но решение будет читаться хуже и будет больше технических деталей
  371. Получили Client Side LB Нахаляву!

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

  373. Принципы SOA 373 1. Standardized service contract 2. Loose coupling

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

    3. Encapsulation 4. Reusability 5. Autonomy 6. Statelessness 7. Discoverability
  375. 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
  376. Парадокс централизации Чтобы эффективно разрабатывать распределённые приложения, нам нужны очень

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

    хорошие централизованные библиотеки и инструменты Но: не выносите бизнес-логику или доменные объекты! Не размывайте бизнес-контекст вашего API 377
  378. Управление конфигурацией

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

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

    examinator-dev.yml
  381. 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: адрес репозитория
  382. 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} • ...
  383. Проблема курица и яйца Откуда брать координаты eureka? • из

    сonfig-server (для всех же одинаковые) • из локальных настроек (ENV/*.yml/etc) Откуда брать координаты сonfig-server • из eureka • из локальных настроек (ENV/*.yml/etc)
  384. App Instance #0 App Instance #N Config Server Eureka Bootstrap

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

    Server URL ИЛИ
  386. Config Server Discovery Через Service Discovery App Instance #0 App

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

    Instance #N Eureka Config Server register on start get Config Server by name
  388. 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
  389. 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
  390. Config Server Discovery По прямой ссылке App Instance #0 App

    Instance #N Config Server get configs for App Http Load Balancer
  391. Config Client • интегрируем config-server и *-service через eureka •

    включаем/отключаем management.security
  392. Обновление на лету @RefreshScope

  393. Начнём с примера @RestController @RefreshScope public class TestController { @Value("${foo.bar}")

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

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

    String test; @GetMapping("/foo") public String getFooBar() { return test; } }
  396. Три простых шага 1. Ставим @RefreshScope над бином который нужно

    обновлять 2. Обновляем в config server foo.bar: some val a. Можно не править а дёрнуть /env если есть actuator 3. Дёргаем у приложения /refresh a. Для этого нужен actuator
  397. А как обновить всё разом?

  398. Spring Cloud Bus

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

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

    APP Discovery Server ALL APP ALL APP
  401. 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' }
  402. Настройки в сonfig server application.yml spring: rabbitmq: host: localhost port:

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

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

    при получении refresh ивента в rabbitmq 2. Для автоматизации можно использовать config-monitor + git webhook compile 'org.springframework.cloud:spring-cloud-config-monitor' 3. Не забывать @RefreshScope
  405. spring-cloud-config-monitor GitHub commit Config Monitor webhook Queue refresh event

  406. spring-cloud-config-monitor Config Server Экзаминатор Экзаминатор GitHub commit Config Monitor webhook

    Queue refresh event Теология Теология Теология ... auto /refresh on event
  407. Spring Cloud Gateway

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

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

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

    APP Discovery Server ALL APP ALL APP Экзаминатор
  411. Экзаминатор:8080 Экзаминатор:8081 Экзаминатор:8082 Экзаминатор:32634 Экзаминатор:...

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

    Server ALL APP Discovery Server ALL APP ALL APP
  413. Reverse Proxy Problem @EnableZuulProxy vs @EnableZuulServer Spring boot 1.x.x

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

    boot 1.x.x
  415. Зависимости 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
  416. Зависимости 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
  417. Был Zuul, стал cloud gateway - зачем?

  418. Почему стоит мигрировать? • Zuul устарел и почти не поддерживается,

    Zuul 2 ждали долго • Zuul не совместим с Spring Boot 2.1 • Spring Cloud Gateway работает на Netty • Spring Cloud Gateway имеет сильно больше фильтров “из коробки”
  419. Роутинг в конфигурации zuul zuul: ignoredServices: '*' routes: student: path:

    /exam/** stripPrefix: true serviceId: examinator
  420. 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")); } ...
  421. 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; } }
  422. Роутинг в конфигурации gateway spring: cloud: gateway: routes: - id:

    math uri: lb://math predicates: - Path=/math/**
  423. 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(); }
  424. Gateway • Создаем проект с gateway • Подключаем его к

    service-discovery • Пишем конфигурацию для роутинга в examinator
  425. Сказка о балансировщике который не смог

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

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

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

    LB App Level LB
  429. Сказка о балансировщике который не смог 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
  430. Сказка о балансировщике который не смог 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
  431. Сказка о балансировщике который не смог 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
  432. Сказка о балансировщике который не смог 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
  433. Защити себя сам 433

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

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

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

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

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

    Service Insurance Service 300мс
  439. 439 Circuit Breaker

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

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

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

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

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

    Service Insurance Service 5мс
  445. Уиии, хочу hystrix!!!

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

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

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

    Timeout • Механизм BulkHead
  449. Режимы работы • Threads • Semaphore

  450. Rent Service Payment Service Security Service Blockchain Service Insurance Service

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

    threadpool size connection timeout read timeout timeout x = 20 настроек
  452. 452 Хочу бегемота! Rent Service Payment Service Security Service Blockchain

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

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

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

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

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

    Service Insurance Service Open Да блин!
  459. Прохождение запроса в системе

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

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

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

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

  464. 464

  465. hystrix/apache camel/akka 465

  466. 466 Spring boot 1.x.x

  467. Hystrix устарел

  468. Новичок resilience4j

  469. Отличия

  470. Отличия • Более легковесный (из коробки тянет только vavr) •

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

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

    Не пытается сам управлять пулом потоков • Нет request collapser • Есть rate limiter • Есть retry • Удобное оборачивание методов “слоями” в функциональном стиле или набором аннотаций • Собранные “обертки” можно переиспользовать
  473. Gateway • Делаем так, чтобы один из сервисов(java,math) возращал ошибку

    в 50% случаев • Подключаем hystrix и настраиваем для него cicruitbreaker на закрытие • Пишем конфигурацию для роутинга в examinator
  474. … но инструмент все еще не решит все проблемы сам

    :)
  475. 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
  476. Следи за своим ПО 476

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

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

    478
  479. spring-cloud-sleuth/open zipkin 479

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

    SpanId = A
  481. 481 Rent Service Payment Service No TraceId No SpanId TraceId

    = X SpanId = A TraceId = X SpanId = B TraceId = X SpanId = C
  482. 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
  483. 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
  484. 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
  485. 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
  486. 486

  487. 487

  488. 488 Rent Service Payment Service

  489. 489 Rent Service Payment Service SpanId = B Client Send

    TraceId = X SpanId = A
  490. 490 Rent Service Payment Service SpanId = B Client Send

    SpanId = B Server Received TraceId = X SpanId = A TraceId = X SpanId = C
  491. 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
  492. 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
  493. documentation → smart documentation 493

  494. 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
  495. 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
  496. 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
  497. Payment Service[jar,doc] Insurance Service [jar,doc] One Point of View [UberDoc.zip]

    Rent Service[jar,doc] Other Service [jar,doc] Агрегация информации 497
  498. Парадокс централизации Чтобы эффективно разрабатывать распределённые приложения, нам нужны очень

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

    хорошие централизованные библиотеки и инструменты Но: не выносите бизнес-логику или доменные объекты! Не размывайте бизнес-контекст вашего API 499
  500. Пришло время поговорить про Reactive

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

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

  503. Reactive manifesto Отзывчивость Эластичность Стабильность Асинхронное адресное общение * *

    у сообщения есть адресат * топология системы динамическая * компоненты слабо связаны
  504. И как это сделать?

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

  506. Reactive manifesto Отзывчивость Эластичность Стабильность Асинхронное адресное общение * *

    у сообщения есть адресат * топология системы динамическая * компоненты слабо связаны
  507. Изоляция сбоев и selfhealing...

  508. Reactive manifesto Отзывчивость Эластичность Стабильность Асинхронное адресное общение * *

    у сообщения есть адресат * топология системы динамическая * компоненты слабо связаны
  509. Слабая связность...

  510. Reactive manifesto Отзывчивость Эластичность Стабильность Асинхронное адресное общение * *

    у сообщения есть адресат * топология системы динамическая * компоненты слабо связаны
  511. Стримминг на всех уровнях

  512. Reactive manifesto Отзывчивость Эластичность Стабильность Асинхронное адресное общение * *

    у сообщения есть адресат * топология системы динамическая * компоненты слабо связаны
  513. NIO и MQ

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

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

    Service Insurance Service Sync Sync Sync
  516. Controller Service HttpClient DBClient

  517. Controller Service HttpClient DBClient

  518. Controller Service HttpClient DBClient

  519. Controller Service HttpClient DBClient

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

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

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

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

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

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

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

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

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

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

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

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

  532. Netty. Асинхронный вход Client Client Client Async threads Event loop

    Single thread Selector Delegate
  533. Reactor IPC Netty Controllers Spring WebFlux WebFlux

  534. Reactor IPC Netty Dispatcher Handler Controllers Channel Operations Spring WebFlux

    WebFlux
  535. Reactor IPC Netty WebFlux Dispatcher Handler Controllers Channel Operations Publisher

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

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

    Publisher Spring WebFlux
  538. Ну это на входе, А с другого конца?

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

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

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

  542. Config Client • Пробуем сделать examinator реактивным • Подключаем spring-boot-starter-webflux

    • Возвращаем из контроллера Mono<Exam> • Заменяем RestTemplate на WebClient • Выстраиваем стрим от клиента до контроллера
  543. None
  544. Для чего RPC Чтобы жизнь была легкой

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

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

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

  548. 1. Сборка

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

  550. 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 { } }
  551. 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
  552. 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
  553. 2. Описание

  554. *.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; }
  555. Почему это не сделали в плагине?

  556. None
  557. None