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

Kirill Tolkachev

April 28, 2019
Tweet

More Decks by Kirill Tolkachev

Other Decks in Programming

Transcript

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  16. Родился SOA

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  25. Ситуация

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  46. DOMAIN Driven Design

    View full-size slide

  47. DOMAIN Driven Design
    ● Bounded context
    X X

    View full-size slide

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

    View full-size slide

  49. ● Context map
    DOMAIN Driven Design

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  53. DOMAIN Driven Design
    Entity
    Logic

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  79. Spring {Boot,Cloud}
    Workshop

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  84. 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

    View full-size slide

  85. web.xml

    org.springframework.web.context.ContextLoaderListener


    springSecurityFilterChain
    org.springframework.web.filter.DelegatingFilterProxy


    springSecurityFilterChain
    /*


    mvc-dispatcher
    org.springframework.web.servlet.DispatcherServlet
    1


    mvc-dispatcher
    /

    View full-size slide



  86. contextClass param-name>
    …AnnotationConfigWebApplicationContext param-value>


    contextConfigLocation param-name>
    com.inwhite.conf.AppConfig param-value>


    View full-size slide

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

    View full-size slide

  88. 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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  92. WebApplicationInitializer

    View full-size slide

  93. ServletContainerInitializer

    View full-size slide

  94. WebApplicationInitializer

    View full-size slide

  95. ServletContainerInitializer

    View full-size slide

  96. § 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.+

    View full-size slide

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

    View full-size slide

  98. § 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.+

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  102. SPI
    org.springframework.web.SpringServletContainerInitializer
    content

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  109. @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));
    }

    View full-size slide

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

    View full-size slide

  111. Spring
    ServletContainer
    Initializer
    tomcat 7
    Spring
    Jar

    View full-size slide

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

    View full-size slide

  113. WebApplicationInitializer
    W
    AI
    WAI
    tomcat 7
    JARS

    View full-size slide

  114. W
    AI
    WAI
    SpringServletContainerInitializer
    tomcat 7

    View full-size slide

  115. 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("/*");
    }

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  118. Как выглядит наш pom.xml

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

    View full-size slide


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


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

    View full-size slide

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

    View full-size slide

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

    View full-size slide




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



    View full-size slide

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

    View full-size slide

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

    View full-size slide

  125. Как выглядит наш 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

    View full-size slide

  126. Как выглядит наш 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'
    }
    }

    View full-size slide

  127. А я не понял

    View full-size slide

  128. Web Starter ТАЩИТ!

    View full-size slide

  129. Кто всё пакует



    org.springframework.boot
    spring-boot-maven-plugin



    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  134. Анатомия 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/
    ...

    View full-size slide

  135. 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/
    ...

    View full-size slide

  136. 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

    View full-size slide

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

    View full-size slide




  138. org.springframework.boot
    spring-boot-maven-plugin

    conference...OurMainClass




    MANIFEST.MF
    ...
    Start-Class: conference.spring.boot.ripper.OurMainClass
    ...

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  141. Хочу 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

    View full-size slide

  142. Demo. Executable jar

    View full-size slide

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

    View full-size slide

  144. Demo. jar structure

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  152. Типы ConfigurableApplicationContext

    View full-size slide

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

    View full-size slide

  154. Web Context Generic Context

    View full-size slide

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

    View full-size slide

  156. Web Context Generic Context

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  164. AOP
    ● Joint Point
    ● Pontcut
    ● Advise
    ● Aspect

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  167. Что за 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).

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  170. @SpringBootApplication

    View full-size slide

  171. @SpringBootApplication
    → @ComponentScan
    → @Configuration
    → @EnableAutoConfiguration

    View full-size slide

  172. @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 {

    View full-size slide

  173. @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 {

    View full-size slide

  174. @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 {};
    }

    View full-size slide

  175. @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 {};
    }

    View full-size slide

  176. @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

    View full-size slide

  177. @EnableAutoConfiguration
    ImportSelector
    Web Starter Boot Starter

    Starter
    Mongo Starter

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  183. 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);
    }

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  189. @ConditionalOn***

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  194. 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 ФабрикаГильотин( "хрусть хрусть"); }
    }

    View full-size slide

  195. 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. Будет отлично работать

    View full-size slide

  196. 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. Будет отлично работать

    View full-size slide

  197. Потому что ASM

    View full-size slide

  198. 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;
    }
    Что если нужно изменить?

    View full-size slide

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

    View full-size slide

  200. 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("/*");
    }

    View full-size slide

  201. 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("/*");
    }

    View full-size slide

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

    View full-size slide

  203. 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);
    }
    }

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  207. § 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);
    }
    }

    View full-size slide

  208. § 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);
    }
    }

    View full-size slide

  209. § 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);
    }
    }
    Работает по
    разному

    View full-size slide

  210. § 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);
    }
    }

    View full-size slide

  211. § 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

    View full-size slide

  212. § 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 плагины
    Обязательно

    View full-size slide

  213. § 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);
    }
    }
    Опционально

    View full-size slide

  214. § 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 контейнере
    Опционально

    View full-size slide

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

    View full-size slide

  216. А как убрать 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.

    View full-size slide

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

    View full-size slide

  218. Анатомия 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

    View full-size slide

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

    View full-size slide

  220. Замочили web.xml

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  226. @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() { }

    View full-size slide

  227. @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() { }

    View full-size slide

  228. @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() { }

    View full-size slide

  229. @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)
    { }

    View full-size slide

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

    View full-size slide

  231. 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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  239. 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": "петух"
    }]
    }]
    }

    View full-size slide

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

    View full-size slide

  241. 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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  254. → Если вы настраиваете руками:
    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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  262. Задание 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

    View full-size slide

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

    View full-size slide

  264. Конфликт портов — 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}}'

    View full-size slide

  265. 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": "петух"
    }]
    }]
    }

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  269. Дальше пишем 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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  272. Как задать 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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  275. 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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  279. 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);

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    → RPC подход

    View full-size slide

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

    View full-size slide

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


    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  303. Service Registry

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  306. Service Registry

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  314. Service
    Eureka
    Marathon
    Marathon Lb

    View full-size slide

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

    View full-size slide

  316. 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

    View full-size slide

  317. Собственный 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

    View full-size slide

  318. Переводим на 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'

    View full-size slide

  319. Переводим на 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'

    View full-size slide

  320. Переводим на 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

    View full-size slide

  321. @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

    View full-size slide

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

    View full-size slide

  323. @EnableEurekaServer
    open http://localhost:8761

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  327. {
    "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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  333. Health checks
    starting

    View full-size slide

  334. Health checks
    http available
    starting

    View full-size slide

  335. Health checks
    app available
    http available
    starting

    View full-size slide

  336. Health checks
    marathon window
    app available
    http available
    starting

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  339. Self preservation

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  345. 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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  350. @EnableEurekaServer
    open http://localhost:8761
    HTTP_ADVERTIZED_PORT

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  363. 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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  369. 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: адрес репозитория

    View full-size slide

  370. 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}
    ● ...

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  376. 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

    View full-size slide

  377. 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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  386. Spring Cloud Bus

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  389. 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'
    }

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  395. Spring Cloud Gateway

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  403. Зависимости 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

    View full-size slide

  404. Зависимости 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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  408. 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"));
    }
    ...

    View full-size slide

  409. 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;
    }
    }

    View full-size slide

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

    View full-size slide

  411. 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();
    }

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  417. Сказка о балансировщике который не смог
    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

    View full-size slide

  418. Сказка о балансировщике который не смог
    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

    View full-size slide

  419. Сказка о балансировщике который не смог
    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

    View full-size slide

  420. Сказка о балансировщике который не смог
    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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  427. 439
    Circuit Breaker

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  451. hystrix/apache camel/akka
    465

    View full-size slide

  452. 466
    Spring boot 1.x.x

    View full-size slide

  453. Hystrix устарел

    View full-size slide

  454. Новичок resilience4j

    View full-size slide

  455. Отличия

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  461. 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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  465. spring-cloud-sleuth/open zipkin
    479

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  468. 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

    View full-size slide

  469. 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

    View full-size slide

  470. 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

    View full-size slide

  471. 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

    View full-size slide

  472. 488
    Rent Service
    Payment Service

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  475. 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

    View full-size slide

  476. 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

    View full-size slide

  477. documentation → smart documentation
    493

    View full-size slide

  478. 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

    View full-size slide

  479. 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

    View full-size slide

  480. 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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  499. Controller Service
    HttpClient
    DBClient

    View full-size slide

  500. Controller Service
    HttpClient
    DBClient

    View full-size slide

  501. Controller Service
    HttpClient
    DBClient

    View full-size slide

  502. Controller Service
    HttpClient
    DBClient

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  516. Reactor IPC
    Netty
    Controllers
    Spring WebFlux
    WebFlux

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  530. 1. Сборка

    View full-size slide

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

    View full-size slide

  532. 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 { }
    }

    View full-size slide

  533. 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

    View full-size slide

  534. 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

    View full-size slide

  535. 2. Описание

    View full-size slide

  536. *.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;
    }

    View full-size slide

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

    View full-size slide