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

Spring Boot И Не Только

Spring Boot И Не Только

В программе
* spring boot
* способы его расширения и заточки под нужды компании
* сложности возникающие при масштабировании подходов работы с микросервисами
* подходы к их решению с помощью spring boot и gradle
* немного о том как работать в команде и к чему нужно стремиться

Учитесь, развивайтесь, ходите на конференции :)

Промокоды на конференции в 2020 году:
https://jpoint.ru/ – JavaMentorJpointPC
http://heisenbug.ru/ – JavaMentorHeisenbugPC

Kirill Tolkachev

March 01, 2020
Tweet

More Decks by Kirill Tolkachev

Other Decks in Technology

Transcript

  1. @tolkv
    @lavcraft
    2

    View full-size slide

  2. Особая благодарность
    @gorelikoff
    @gorelikov
    3

    View full-size slide

  3. В конце полезняшки
    — ???
    — ???
    4

    View full-size slide

  4. Начнём?
    Господин Best Practice
    Господин «Аастанавись, Задумайся»
    Господин тимлид – он за контроль
    Господин «№;$?% Магия…»
    Господин, который просто
    классно шутит 5

    View full-size slide

  5. Spring Boot
    новые методы решения для новых проблем

    View full-size slide

  6. Spring Boot
    Как??? Зачем?!
    City
    Как тут
    выжить?

    View full-size slide

  7. Цели Мы пошли в микросервисы,
    какие проблемы ожидать и как
    их решать?
    8

    View full-size slide

  8. Цели Мы пошли в микросервисы,
    какие проблемы ожидать и как
    их решать?
    Чем разработчику могут
    помочь Spring Boot и другие
    инструменты, и какие могут
    быть проблемы?
    9

    View full-size slide

  9. Disclaimer
    10

    View full-size slide

  10. Disclaimer
    Слушайте нас,
    но используйте свои мозги
    11

    View full-size slide

  11. Disclaimer
    Слушайте нас,
    но используйте свои мозги
    Писать код не будем – есть доки
    Только опыт, логика и выводы
    12

    View full-size slide

  12. Live. Die. REPEAT
    Внимание могут быть повторы , но это нормально

    View full-size slide

  13. План
    1. Spring boot
    2. Spring Boot
    3. Что-то еще
    4. Перерыв
    5. Spring Boot
    6. Выводы
    14

    View full-size slide

  14. А на чем вообще пишут сервисы?
    15

    View full-size slide

  15. И как выбирают?
    16

    View full-size slide

  16. И как выбирают?
    Корпоративный стандарт
    1. Только Java
    2. Только Java EE
    3. Только Oracle
    4. Только
    От компании
    17

    View full-size slide

  17. И как выбирают?
    Корпоративный стандарт
    1. Только Java
    2. Только Java EE
    3. Только Oracle
    4. Только
    Какой стандарт?
    1. Go
    2. Rust
    3. Unicorn
    4. Смузи
    От компании От разработчика
    18

    View full-size slide

  18. Ну, а если серьезно?
    ● Обладает нужной функциональностью
    ● Вписывается в нефункциональные требования
    ● Поддержка и количество тем на stackoverflow
    ● Знания и интересы команды
    19

    View full-size slide

  19. Серьезно?
    ● Обладает нужной функциональностью
    ● Вписывается в нефункциональные требования
    ● Поддержка и количество тем на stackoverflow
    ● Знания и интересы команды
    20

    View full-size slide

  20. Выбирать по
    функциональности и
    поддержке
    Компетенции команды изменчивы

    View full-size slide

  21. Кто про что,
    а мы про...
    SPRING BOOT

    View full-size slide

  22. Spring уже не магия
    24

    View full-size slide

  23. Spring Boot все еще магия
    25

    View full-size slide

  24. Что такое
    Spring Boot?
    Эта jar-ник c
    Tomcat внутри
    Java interview 2014
    26

    View full-size slide

  25. Java interview 2017
    Что такое
    Spring Boot?
    Эта хрень
    помогает
    проще собрать
    микросервис
    27

    View full-size slide

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

    View full-size slide

  27. Но новичкам-то нравится
    29

    View full-size slide

  28. Пока не приходит
    Spring Boot инквизиция
    30

    View full-size slide

  29. Spring Boot
    слишком
    Самостоятелен
    © «КакойТо» team-lead
    31

    View full-size slide

  30. Откуда 436 spring beans?
    32

    View full-size slide

  31. Откуда 436 spring beans?
    33

    View full-size slide

  32. Кто прав?
    34

    View full-size slide

  33. Нельзя любить или не
    любить инструмент
    В нем нужно разбираться

    View full-size slide

  34. Давайте разберёмся в “магии”
    36

    View full-size slide

  35. Кто был на “Spring is coming”?
    37

    View full-size slide

  36. Смотрим код Spring Boot’a
    38

    View full-size slide

  37. @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 {
    … 39

    View full-size slide

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

    View full-size slide

  39. AutoConfigurationImportSelect
    or
    protected List getCandidateConfigurations(...) {
    List configurations = SpringFactoriesLoader.loadFactoryNames(
    getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader());
    ...
    return configurations;
    }
    41

    View full-size slide

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

    129 lines
    42

    View full-size slide

  41. @SpringBootApplication
    43

    View full-size slide

  42. @SpringBootApplication
    @EnableAutoConfiguration
    44

    View full-size slide

  43. @SpringBootApplication
    @EnableAutoConfiguration
    ImportSelector
    45

    View full-size slide

  44. @SpringBootApplication
    @EnableAutoConfiguration
    ImportSelector
    SpringFactoriesLoader
    46

    View full-size slide

  45. @SpringBootApplication
    @EnableAutoConfiguration
    ImportSelector
    SpringFactoriesLoader
    Starter#1 Starter#2 Starter#3
    47

    View full-size slide

  46. Ваше
    приложение
    48

    View full-size slide

  47. @ConditionalOnClass
    @ConditionalOnBean
    @ConditionalOnExpression
    @ConditionalOnProperty
    @ConditionalOnResource
    Загрузка при условии
    49

    View full-size slide

  48. spring-boot-autoconfigure.jar
    /spring.factories
    org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
    ...
    org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\
    ...
    129 lines
    50

    View full-size slide

  49. @ConditionalOnClass({ RabbitTemplate.class, Channel.class })
    Загрузка при условии
    51

    View full-size slide

  50. Тимлид доволен
    Молодца!
    Ничего лишнего
    52

    View full-size slide

  51. Прошло полгода
    53

    View full-size slide

  52. Из чего состоит
    сервис?
    54

    View full-size slide

  53. Из чего состоит
    сервис?
    ● API
    55

    View full-size slide

  54. Из чего состоит
    сервис?
    ● API
    ● Clients
    ○ JSON
    ○ SOAP
    56

    View full-size slide

  55. Из чего состоит
    сервис?
    ● API
    ● Clients
    ○ JSON
    ○ SOAP
    ● Cloud
    ○ Discovery
    ○ Config
    57

    View full-size slide

  56. Из чего состоит
    сервис?
    ● API
    ● Clients
    ○ JSON
    ○ SOAP
    ● Cloud
    ○ Discovery
    ○ Config
    ● Metrics
    ○ Healthcheck
    ○ Logs
    58

    View full-size slide

  57. Из чего состоит
    сервис?
    ● API
    ● Clients
    ○ JSON
    ○ SOAP
    ● Cloud
    ○ Discovery
    ○ Config
    ● Metrics
    ○ Healthcheck
    ○ Logs
    ● Data
    ● Stream
    59

    View full-size slide

  58. Смотрим код сервиса
    60

    View full-size slide

  59. Так это выглядит изнутри...
    61

    View full-size slide

  60. Так это выглядит изнутри...
    62

    View full-size slide

  61. Так это выглядит изнутри...
    63

    View full-size slide

  62. Так это выглядит изнутри...
    64

    View full-size slide

  63. Так это выглядит изнутри...
    65

    View full-size slide

  64. Так это выглядит изнутри...
    66

    View full-size slide

  65. Так это выглядит изнутри...
    67

    View full-size slide

  66. Этим сервисам стоило бы
    похудеть
    68

    View full-size slide

  67. Я не толстый!
    у меня кость широкая 69

    View full-size slide

  68. Так это выглядит изнутри...
    70

    View full-size slide

  69. Что в этих классах
    71

    View full-size slide

  70. Service discovery
    72

    View full-size slide

  71. Межсервисное общение
    73

    View full-size slide

  72. Межсервисное общение
    74

    View full-size slide

  73. Межсервисное общение
    75

    View full-size slide

  74. Межсервисное общение
    76

    View full-size slide

  75. Межсервисное общение
    1.0
    1.0
    1.0
    77

    View full-size slide

  76. Межсервисное общение
    2.0
    1.0
    1.0
    78

    View full-size slide

  77. Простое общение с
    @FeignClient("cards-api")
    public interface P2PCardService {
    @RequestMapping(value = "/", method = RequestMethod.POST)
    CardDTO loadDetachedCard(String id);
    }
    79

    View full-size slide

  78. Отфильтруем друзей
    public class ServiceAPIVersionServerListFilter extends ZoneAffinityServerListFilter {
    ...
    @Override
    public List getFilteredListOfServers(List listOfServers) {
    if (listOfServers == null || listOfServers.isEmpty()) return listOfServers;
    List infos = this.discoveryClient.getInstances(listOfServers.first()
    .getMetaInfo()
    .getServiceIdForDiscovery());
    final List versionedInstance = infos.stream()
    .filter(instanceInfo -> !versions.containsKey(instanceInfo.getServiceId().toLowerCase())
    || checkVersion(versions.get(instanceInfo.getServiceId().toLowerCase()),
    instanceInfo.getMetadata().get(VERSION_FIELD)))
    .collect(Collectors.toList());
    return listOfServers.stream()
    .filter(server -> checkServiceInstance(server, versionedInstance)) 80

    View full-size slide

  79. Отфильтруем друзей
    public class ServiceAPIVersionServerListFilter extends ZoneAffinityServerListFilter {
    ...
    @Override
    public List getFilteredListOfServers(List listOfServers) {
    if (listOfServers == null || listOfServers.isEmpty()) return listOfServers;
    List infos = this.discoveryClient.getInstances(listOfServers.first()
    .getMetaInfo()
    .getServiceIdForDiscovery());
    final List versionedInstance = infos.stream()
    .filter(instanceInfo -> !versions.containsKey(instanceInfo.getServiceId().toLowerCase())
    || checkVersion(versions.get(instanceInfo.getServiceId().toLowerCase()),
    instanceInfo.getMetadata().get(VERSION_FIELD)))
    .collect(Collectors.toList());
    return listOfServers.stream()
    .filter(server -> checkServiceInstance(server, versionedInstance)) 81

    View full-size slide

  80. Отфильтруем друзей
    public class ServiceAPIVersionServerListFilter extends ZoneAffinityServerListFilter {
    ...
    @Override
    public List getFilteredListOfServers(List listOfServers) {
    if (listOfServers == null || listOfServers.isEmpty()) return listOfServers;
    List infos = this.discoveryClient.getInstances(listOfServers.first()
    .getMetaInfo()
    .getServiceIdForDiscovery());
    final List versionedInstance = infos.stream()
    .filter(instanceInfo -> !versions.containsKey(instanceInfo.getServiceId().toLowerCase())
    || checkVersion(versions.get(instanceInfo.getServiceId().toLowerCase()),
    instanceInfo.getMetadata().get(VERSION_FIELD)))
    .collect(Collectors.toList());
    return listOfServers.stream()
    .filter(server -> checkServiceInstance(server, versionedInstance)) 82

    View full-size slide

  81. 83
    Это что?!

    View full-size slide

  82. Много странного кода
    public class ServiceAPIVersionServerListFilter extends ZoneAffinityServerListFilter {
    ...
    @Override
    public List getFilteredListOfServers(List listOfServers) {
    if (listOfServers == null || listOfServers.isEmpty()) return listOfServers;
    List infos = this.discoveryClient.getInstances(listOfServers.first()
    .getMetaInfo()
    .getServiceIdForDiscovery());
    final List versionedInstance = infos.stream()
    .filter(instanceInfo -> !versions.containsKey(instanceInfo.getServiceId().toLowerCase())
    || checkVersion(versions.get(instanceInfo.getServiceId().toLowerCase()),
    instanceInfo.getMetadata().get(VERSION_FIELD)))
    .collect(Collectors.toList());
    return listOfServers.stream()
    .filter(server -> checkServiceInstance(server, versionedInstance)) 84

    View full-size slide

  83. В нашем сервисе есть что-то инородное
    85

    View full-size slide

  84. Надо переносить в
    библиотеки
    86

    View full-size slide

  85. Стоп! Задумаемся
    87

    View full-size slide

  86. Стоп! Задумаемся
    Как конфигурировать?
    88

    View full-size slide

  87. Конфигурация фильтра
    eureka:
    client:
    registryFetchIntervalSeconds: 5
    serviceUrl:
    defaultZone: ${EUREKA_SERV:http://127.0.0.1:8763/eureka/}
    instance:
    virtualHostName : ${spring.application.name}
    metadataMap:
    instanceId: ${spring.application.name}:${random.value}
    versions: ["1.0", "2.0"]
    spring:
    discovery:
    filter:
    versions:
    someServiceId: 1.0 89

    View full-size slide

  88. Конфигурация фильтра
    eureka:
    client:
    metadataMap:
    versions: ["1.0", "2.0"]
    spring:
    discovery:
    filter:
    versions:
    someServiceId: 1.0
    90

    View full-size slide

  89. Конфигурация фильтра
    eureka:
    client:
    metadataMap:
    versions: ["1.0", "2.0"]
    spring:
    discovery:
    filter:
    versions:
    someServiceId: 1.0
    2.0
    1.0
    91

    View full-size slide

  90. Конфигурация фильтра
    eureka:
    client:
    metadataMap:
    versions: ["1.0", "2.0"]
    spring:
    discovery:
    filter:
    versions:
    someServiceId: 1.0 1.0
    2.0
    1.0
    2.0
    92

    View full-size slide

  91. Конфигурация фильтра
    eureka:
    client:
    metadataMap:
    versions: ["1.0", "2.0"]
    spring:
    discovery:
    filter:
    versions:
    someServiceId: 1.0
    93

    View full-size slide

  92. Хочется видеть что-то такое
    spring:
    discovery:
    filter:
    versions:
    someServiceId: 1.0
    api:
    versions: ["1.0", "2.0"]
    94

    View full-size slide

  93. Надо просто переложить
    spring:
    discovery:
    api:
    versions: ["1.0", "2.0"]
    eureka:
    client:
    metadataMap:
    versions: ["1.0", "2.0"]
    95

    View full-size slide

  94. spring:
    discovery:
    filter:
    versions:
    someServiceId: 1.0
    api:
    versions: ["1.0", "2.0"]
    Хочется видеть что-то такое
    И проверять!!!
    96

    View full-size slide

  95. ERROR [-,,,] 27393 --- [main] o.s.boot.SpringApplication: Application startup failed
    Error java.lang.IllegalStateException: Version of supported API should be specified, e.g.:
    spring:
    discovery:
    api:
    versions: ["1.0", "2.0"]
    Run Application
    97

    View full-size slide

  96. EnvironmentPostProcessor
    public class PropertyTranslatorPostProcessor implements EnvironmentPostProcessor {
    @Override
    public void postProcessEnvironment(ConfigurableEnvironment env,
    SpringApplication application) { }
    translateClientVersionProperty(env);
    translateZuulRoutes(env);
    }

    }
    98

    View full-size slide

  97. @Configuration
    public class DiscoveryVersionFilterConfiguration {
    @Bean
    public void propertyTranslator() { }
    return new PropertyTranslatorPostProcessor();
    }

    }
    Создаём EPP
    99

    View full-size slide

  98. Чёт
    жужжит, но
    ничего не
    происходит
    100

    View full-size slide

  99. Не работает
    ваша магия
    101

    View full-size slide

  100. EnvironmentPostProcessor`s
    Application
    ContextInitializer`s
    Application
    ReadyEvent
    Тут начинается
    Spring Ripper
    Application
    StartingEvent
    Application
    EnvironmentPreparedEvent
    Application
    PreparedEvent
    Context
    RefreshedEvent
    EmbeddedServlet
    Container
    InitializedEvent
    102

    View full-size slide

  101. EnvironmentPostProcessor`s
    Application
    ContextInitializer`s
    Application
    ReadyEvent
    Тут начинается
    Spring Ripper
    Application
    StartingEvent
    Application
    EnvironmentPreparedEvent
    Application
    PreparedEvent
    Context
    RefreshedEvent
    EmbeddedServlet
    Container
    InitializedEvent
    103

    View full-size slide

  102. EnvironmentPostProcessor`s
    Application
    ContextInitializer`s
    Application
    ReadyEvent
    Тут начинается
    Spring Ripper
    Application
    StartingEvent
    Application
    EnvironmentPreparedEvent
    Application
    PreparedEvent
    Context
    RefreshedEvent
    EmbeddedServlet
    Container
    InitializedEvent
    104

    View full-size slide

  103. запуск
    SpringApplicationInitializer
    Локальные бины
    приложения созданы
    ApplicationEnvironment
    PreparedEvent
    запуск
    EnvironmentPostPorcessors
    Пользовательские
    бины создаются
    слишком поздно
    105

    View full-size slide

  104. Надо выносить в
    автоконфигурацию
    106

    View full-size slide

  105. Автоконфигурация же внутри
    Spring?
    107

    View full-size slide

  106. Как устроен стартер
    108

    View full-size slide

  107. Autoconfigure
    109

    View full-size slide

  108. Условия
    @Configuration
    @ConditionalOnBean({Client.class, DiscoveryClient.class})
    @EnableConfigurationProperties(value = APIVersionFilterProperties.class)
    public class DiscoveryAPIVersionFilterAutoConfiguration {
    @Bean
    public ApiVersionServerListFilter versionedFilter(DiscoveryClient discoveryClient,
    APIVersionFilterProperties properties) {
    return new APIVersionServerListFilter(properties.getServiceVersions(), discoveryClient);
    }
    ...
    }
    110

    View full-size slide

  109. Конфигурация
    @Configuration
    @ConditionalOnBean({Client.class, DiscoveryClient.class})
    @EnableConfigurationProperties(value = APIVersionFilterProperties.class)
    public class DiscoveryAPIVersionFilterAutoConfiguration {
    @Bean
    public ApiVersionServerListFilter versionedFilter(DiscoveryClient discoveryClient,
    APIVersionFilterProperties properties) {
    return new APIVersionServerListFilter(properties.getServiceVersions(), discoveryClient);
    }
    ...
    }
    111

    View full-size slide

  110. spring.factories
    org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
    ru.alfalab.discovery.version.DiscoveryAPIVersionFilterAutoConfiguration
    org.springframework.boot.env.EnvironmentPostProcessor=\
    ru.alfalab.discovery.version.property.PropertyTranslatorPostProcessor
    113

    View full-size slide

  111. Вся магия
    1. @EnableAutoConfiguration
    2. @ConditionalOn…
    3. spring.factories
    114

    View full-size slide

  112. Вся магия
    1. @EnableAutoConfiguration
    2. @ConditionalOn…
    3. spring.factories
    Все не так
    сложно, как
    кажется
    115

    View full-size slide

  113. Псс, код посмотреть
    хочешь?

    View full-size slide

  114. Подробнее – смотри доклад
    Boot Yourself, Spring is
    Coming
    https://habr.com/ru/company/jugru/blog/424503/
    https://habr.com/ru/company/jugru/blog/425333/

    View full-size slide

  115. Дело не в spring-cloud
    → Умное логирование
    → Web-фильтры с доп. логикой
    → Любые другие расширения базовых механизмов
    118

    View full-size slide

  116. Доработка и расширение
    механизмов Spring должны
    быть в стартерах
    используй инструменты в соответствии с уже заложенными
    принципами

    View full-size slide

  117. Все еще много лишнего?
    120

    View full-size slide

  118. Все равно толстый!
    121

    View full-size slide

  119. Первый шаг к похуданию
    122

    View full-size slide

  120. Что у них общего?
    123

    View full-size slide

  121. Они общаются по SOAP
    XML
    124

    View full-size slide

  122. SOAP Services and Apache CXF
    ServiceDefinition.wsdl
    xmlns:tns = "http://www.examples.com/wsdl/HelloService.w












    ...

    125

    View full-size slide

  123. SOAP Services and Apache CXF
    ServiceDefinition.wsdl
    xmlns:tns = "http://www.examples.com/wsdl/HelloService.w











    ...

    Java Stub
    wsdl2java tool
    126

    View full-size slide

  124. SOAP Services and Apache CXF
    ServiceDefinition.wsdl
    Java Stub
    wsdl2java tool
    127

    View full-size slide

  125. SOAP Services and Apache CXF
    ServiceDefinition.wsdl
    Java Stub
    wsdl2java tool
    WS Stub in Spring Context
    Configure bean
    128

    View full-size slide

  126. SOAP Services and Apache CXF
    ServiceDefinition.wsdl
    Java Stub
    wsdl2java tool
    WS Stub in Spring Context
    Configure bean

    address="${lb.address.base}/WSCodeClickDynamic
    address="${lb.address.base}/WSClickPaymentPass
    ...
    address="${ws.address.base}/WSCustomerAddress/
    serviceClass="ru.alfalab...wscustomerinfo9.WSC
    address="${lb.address.base}/WSCustomerInfo/WSC

    129

    View full-size slide

  127. SOAP Services and Apache CXF
    ServiceDefinition.wsdl
    Java Stub
    wsdl2java tool
    WS Stub in Spring Context
    Configure bean

    address="${lb.address.base}/WSCodeClickDynamic
    address="${lb.address.base}/WSClickPaymentPass
    ...
    address="${ws.address.base}/WSCustomerAddress/
    serviceClass="ru.alfalab...wscustomerinfo9.WSC
    address="${lb.address.base}/WSCustomerInfo/WSC

    Call Bean
    Inject ws bean
    130

    View full-size slide

  128. SOAP Services and Apache CXF
    Apache CXF
    ServiceDefinition.wsdl
    Java Stub
    wsdl2java tool
    WS Stub in Spring Context
    Configure bean
    Call Bean
    Inject ws bean
    131

    View full-size slide

  129. SOAP Services and Apache CXF
    Apache CXF
    ServiceDefinition.wsdl
    Java Stub
    wsdl2java tool
    WS Stub in Spring Context
    Configure bean
    Call Bean
    Inject ws bean
    132

    View full-size slide

  130. CXF Stub в библиотеки
    133

    View full-size slide

  131. CXF Stub в библиотеки
    dependencies {
    compile 'ru.alfabank.ws:currency-stub:1.0.0'
    }
    134

    View full-size slide

  132. CXF Stub в библиотеки
    ws-stub
    transfers-api
    cards-api
    ...-api
    dependencies {
    compile 'ru.alfabank.ws:currency-stub:1.0.0'
    }
    135

    View full-size slide


  133. serviceClass="ru.alfalab...wscodedynamicfields32.WSCodeDynamicFields31PortType"
    address="${lb.address.base}/WSCodeClickDynamicFields/WSCodeDynamicFields11"/>
    serviceClass="ru.alfalab...wsclickpaymentpassword10.WSPaymentPassword13PortType"
    address="${lb.address.base}/WSClickPaymentPassword/WSPaymentPassword13"/>
    ...
    serviceClass="ru.alfalab...wscustomeraddress22.WSCustomerAddressCompletePortType"
    address="${ws.address.base}/WSCustomerAddress/WSCustomerAddressComplete22"/>
    serviceClass="ru.alfalab...wscustomerinfo9.WSCustomerInfo9PortType"
    address="${lb.address.base}/WSCustomerInfo/WSCustomerInfo9"/>

    WS – ты кто такой
    136

    View full-size slide


  134. serviceClass="ru.alfalab...wscodedynamicfields32.WSCodeDynamicFields31PortType"
    address="${lb.address.base}/WSCodeClickDynamicFields/WSCodeDynamicFields11"/>
    serviceClass="ru.alfalab...wsclickpaymentpassword10.WSPaymentPassword13PortType"
    address="${lb.address.base}/WSClickPaymentPassword/WSPaymentPassword13"/>
    ...
    serviceClass="ru.alfalab...wscustomeraddress22.WSCustomerAddressCompletePortType"
    address="${ws.address.base}/WSCustomerAddress/WSCustomerAddressComplete22"/>
    serviceClass="ru.alfalab...wscustomerinfo9.WSCustomerInfo9PortType"
    address="${lb.address.base}/WSCustomerInfo/WSCustomerInfo9"/>

    WS – ты кто такой
    137

    View full-size slide

  135. WS – ты кто такой
    transactions-api
    – ws.xml
    138

    View full-size slide

  136. WS – ты кто такой
    transactions-api
    – ws.xml
    targeting-api
    – ws.xml
    139

    View full-size slide

  137. WS – ты кто такой
    transactions-api
    – ws.xml
    targeting-api
    – ws.xml
    transfers-api
    – ws.xml
    ...
    140

    View full-size slide

  138. 1. Добавить зависимость (WSDL/WS-STUB)
    2. Настроить бины в ws.xml
    3. Прописать адреса и настройки для добавленных сервисов
    ${lb.address.base}
    Как сделать новый RPC вызов
    141

    View full-size slide

  139. Как сделать новый RPC вызов
    1. Добавить зависимость (WSDL/WS-STUB)
    2. Настроить бины в ws.xml
    3. Прописать адреса и настройки для добавленных сервисов
    ${lb.address.base}
    И как это делается?
    142

    View full-size slide

  140. Как сделать новый RPC вызов
    1. Добавить зависимость (WSDL/WS-STUB)
    2. Настроить бины в ws.xml
    3. Прописать адреса и настройки для добавленных сервисов
    ${lb.address.base}
    И как это делается?
    Captain Copy-Paste 143

    View full-size slide

  141. А что нужно разработчикам?

    View full-size slide

  142. Сервис!
    145

    View full-size slide

  143. Run Application
    ERROR [-,,,] 27393 --- [main] o.s.boot.SpringApplication: Application startup failed
    Error creating bean with name 'ru.alfabank...WSAccountClickPayment13PortType' defined in
    Apache CXF starter autoscan package: Add next properties to your application.yml file:
    spring.cxf:
    clients:
    -
    endpoint: http://SOME_HOST/SOME_PATH_TO_WS
    className: ru.alfabank.ws.cs.eq.wsaccountclickpayment13.WSAccountClickPayment13PortType
    146

    View full-size slide

  144. ERROR [-,,,] 27393 --- [main] o.s.boot.SpringApplication: Application startup failed
    Error creating bean with name 'ru.alfabank...WSAccountClickPayment13PortType' defined in
    Apache CXF starter autoscan package: Add next properties to your application.yml file:
    spring.cxf:
    clients:
    -
    endpoint: http://SOME_HOST/SOME_PATH_TO_WS
    className: ru.alfabank.ws.cs.eq.wsaccountclickpayment13.WSAccountClickPayment13PortType
    Run Application
    147

    View full-size slide

  145. ERROR [-,,,] 27393 --- [main] o.s.boot.SpringApplication: Application startup failed
    Error creating bean with name 'ru.alfabank...WSAccountClickPayment13PortType' defined in
    Apache CXF starter autoscan package: Add next properties to your application.yml file:
    spring.cxf:
    clients:
    -
    endpoint: http://SOME_HOST/SOME_PATH_TO_WS
    className: ru.alfabank.ws.cs.eq.wsaccountclickpayment13.WSAccountClickPayment13PortType
    Process finished with exit code 1
    Run Application
    148

    View full-size slide

  146. Автоматизируем?
    Classpath
    @WebService
    WSAccountClickPayment13PortType
    @WebService
    WSCardsTransactions12PortType
    @Component
    MySuperService
    @Other
    ...
    149

    View full-size slide

  147. Автоматизируем?
    Classpath
    @WebService
    WSAccountClickPayment13PortType
    @WebService
    WSCardsTransactions12PortType
    @Component
    MySuperService
    @Other
    ...
    Find
    WS Classes
    @WebService
    WSAccountClickPayment13PortType
    @WebService
    WSCardsTransactions12PortType
    150

    View full-size slide

  148. Автоматизируем?
    Classpath
    @WebService
    WSAccountClickPayment13PortType
    @WebService
    WSCardsTransactions12PortType
    @Component
    MySuperService
    @Other
    ...
    Find
    WS Classes
    @WebService
    WSAccountClickPayment13PortType
    @WebService
    WSCardsTransactions12PortType
    Spring Context
    BeanDefinition + BeanFactory
    WSAccountClickPayment13PortType
    BeanDefinition + BeanFactory
    WSCardsTransactions12PortType
    Configure Context
    151

    View full-size slide

  149. Автоматизируем?
    Spring Context
    BeanDefinition + BeanFactory
    WSAccountClickPayment13PortType
    BeanDefinition + BeanFactory
    WSCardsTransactions12PortType
    Inject
    Spring Context
    @Component
    MyService
    BeanInstance
    WSCardsTransactions12PortType
    Configure Properties and Endpoints
    152

    View full-size slide

  150. Автоматизируем?
    Spring Context
    BeanDefinition + BeanFactory
    WSAccountClickPayment13PortType
    BeanDefinition + BeanFactory
    WSCardsTransactions12PortType
    Inject
    Spring Context
    @Component
    MyService
    BeanInstance
    WSCardsTransactions12PortType
    Configure Properties and Endpoints
    Или падает с ошибкой
    если не настроен endpoint
    FAIL-FAST
    Error creating bean with name
    'ru.alfabank...WSSomeServicet13PortType' defined in Apache CXF
    starter autoscan package: Add next properties to your
    application.yml file:
    spring.cxf:
    clients:
    -
    endpoint: http://SOME_HOST/SOME_PATH_TO_WS
    className: ru.alfabank....WSSomeServicet13PortType 153

    View full-size slide

  151. EPP нет, можно в обычную
    библиотеку?
    154

    View full-size slide

  152. Как все это подключать?
    155

    View full-size slide

  153. @Slf4j
    @Configuration
    @EnableConfigurationProperties
    @ConditionalOnProperty(name = "spring.cxf.client.enabled", matchIfMissing = true)
    public class CxfClientConfiguration {
    @Bean
    public CxfBeanDefinitionPostProcessor cxfBeanDefinitionPP(Environment environment) {
    return new CxfBeanDefinitionPostProcessor(environment);
    }
    @Bean
    public static BusWiringBeanFactoryPostProcessor jsr250BeanPostProcessor() {
    return new BusWiringBeanFactoryPostProcessor();
    }
    @Bean
    public static BusExtensionPostProcessor busExtensionPostProcessor() {
    return new BusExtensionPostProcessor();
    }
    @Slf4j
    @Configuration
    @ConditionalOnClass({SpringBus.class, JaxWsClientFactoryBean.class, ConfigurationPropertiesBindingPostProcessor.class})
    @EnableConfigurationProperties({CxfClientsProperties.class, WSConfiguration.class})
    public static class CxfClientFactoryAutoConfiguration {
    @Bean(name = CXF_WS_CLIENT_PROXY_FACTORY_DEFAULT_NAME)
    @ConditionalOnMissingBean(name = {CXF_WS_CLIENT_PROXY_FACTORY_DEFAULT_NAME})
    CxfWsStubBeanFactory proxyWsBeanFactory(
    CxfClientsProperties cxfClientsProperties,
    Bus bus,
    CxfInterceptorConfigurer interceptorConfigurer
    ) {
    return new CxfWsStubBeanFactory(
    cxfClientsProperties,
    bus,
    interceptorConfigurer
    );
    }
    Конфигурация библиотек
    @Bean
    @ConditionalOnMissingBean(CxfBusConfigurer.class)
    public CxfBusConfigurer cxfBusConfigurer(CxfClientsProperties cxfClientsProperties) {
    return new DefaultCxfBusConfigurer(cxfClientsProperties);
    }
    @Bean(destroyMethod = "shutdown")
    public Bus cxf(CxfBusConfigurer cxfBusConfigurer) {
    SpringBus bus = new SpringBus();
    cxfBusConfigurer.configure(bus);
    return bus;
    }
    @Bean
    @ConditionalOnMissingBean(CxfInterceptorConfigurer.class)
    public CxfInterceptorConfigurer cxfInterceptorConfigurer(
    CxfInterceptorAnnotationProcessor cxfInterceptorAnnotationProcessor,
    BeanFactory beanFactory
    ) {
    return new CxfInterceptorConfigurer(
    beanFactory,
    cxfInterceptorAnnotationProcessor.getGlobalInterceptors(),
    cxfInterceptorAnnotationProcessor.getSpecificInterceptors()
    );
    }
    @Bean
    @ConditionalOnMissingBean(CxfInterceptorAnnotationProcessor.class)
    public static CxfInterceptorAnnotationProcessor cxfInterceptorBFPP() {
    return new CxfInterceptorAnnotationProcessor();
    }
    static final String CXF_WS_CLIENT_PROXY_FACTORY_DEFAULT_NAME = "CxfWsClientProxyFactory";
    }
    }
    156

    View full-size slide

  154. @Slf4j
    @Configuration
    @EnableConfigurationProperties
    @ConditionalOnProperty(name = "spring.cxf.client.enabled", matchIfMissing = true)
    public class CxfClientConfiguration {
    @Bean
    public CxfBeanDefinitionPostProcessor cxfBeanDefinitionPP(Environment environment) {
    return new CxfBeanDefinitionPostProcessor(environment);
    }
    @Bean
    public static BusWiringBeanFactoryPostProcessor jsr250BeanPostProcessor() {
    return new BusWiringBeanFactoryPostProcessor();
    }
    @Bean
    public static BusExtensionPostProcessor busExtensionPostProcessor() {
    return new BusExtensionPostProcessor();
    }
    @Slf4j
    @Configuration
    @ConditionalOnClass({SpringBus.class, JaxWsClientFactoryBean.class, ConfigurationPropertiesBindingPostProcessor.class})
    @EnableConfigurationProperties({CxfClientsProperties.class, WSConfiguration.class})
    public static class CxfClientFactoryAutoConfiguration {
    @Bean(name = CXF_WS_CLIENT_PROXY_FACTORY_DEFAULT_NAME)
    @ConditionalOnMissingBean(name = {CXF_WS_CLIENT_PROXY_FACTORY_DEFAULT_NAME})
    CxfWsStubBeanFactory proxyWsBeanFactory(
    CxfClientsProperties cxfClientsProperties,
    Bus bus,
    CxfInterceptorConfigurer interceptorConfigurer
    ) {
    return new CxfWsStubBeanFactory(
    cxfClientsProperties,
    bus,
    interceptorConfigurer
    );
    }
    Конфигурация библиотек
    @Bean
    @ConditionalOnMissingBean(CxfBusConfigurer.class)
    public CxfBusConfigurer cxfBusConfigurer(CxfClientsProperties cxfClientsProperties) {
    return new DefaultCxfBusConfigurer(cxfClientsProperties);
    }
    @Bean(destroyMethod = "shutdown")
    public Bus cxf(CxfBusConfigurer cxfBusConfigurer) {
    SpringBus bus = new SpringBus();
    cxfBusConfigurer.configure(bus);
    return bus;
    }
    @Bean
    @ConditionalOnMissingBean(CxfInterceptorConfigurer.class)
    public CxfInterceptorConfigurer cxfInterceptorConfigurer(
    CxfInterceptorAnnotationProcessor cxfInterceptorAnnotationProcessor,
    BeanFactory beanFactory
    ) {
    return new CxfInterceptorConfigurer(
    beanFactory,
    cxfInterceptorAnnotationProcessor.getGlobalInterceptors(),
    cxfInterceptorAnnotationProcessor.getSpecificInterceptors()
    );
    }
    @Bean
    @ConditionalOnMissingBean(CxfInterceptorAnnotationProcessor.class)
    public static CxfInterceptorAnnotationProcessor cxfInterceptorBFPP() {
    return new CxfInterceptorAnnotationProcessor();
    }
    static final String CXF_WS_CLIENT_PROXY_FACTORY_DEFAULT_NAME = "CxfWsClientProxyFactory";
    }
    }
    157

    View full-size slide

  155. Конфигурация библиотек
    @Bean
    public CxfBeanDefinitionPostProcessor cxfBeanDefinitionPP(Environment env) {
    return new CxfBeanDefinitionPostProcessor(env);
    }
    @Bean
    public static BusWiringBeanFactoryPostProcessor jsr250BeanPostProcessor() {
    return new BusWiringBeanFactoryPostProcessor();
    }
    @Bean
    public static BusExtensionPostProcessor busExtensionPostProcessor() {
    return new BusExtensionPostProcessor();
    }
    158

    View full-size slide

  156. Как все это подключать?
    ● Чтение документации
    159

    View full-size slide

  157. Как все это подключать?
    ● Чтение документации
    ● Debug
    160

    View full-size slide

  158. Как все это подключать?
    ● Чтение документации
    ● Debug
    ● Найти того, кто это писал...
    161

    View full-size slide

  159. Есть способ быстрее?!
    162

    View full-size slide

  160. Есть способ быстрее?!
    163

    View full-size slide

  161. Конфигурация библиотек
    Или, не дай бог :
    @ComponentScan(
    {
    "ru.alfa.cxf",
    "ru.alfa.discovery",
    "ru...",
    "ru..."
    ...
    }
    )
    164

    View full-size slide

  162. Проблемы
    1. Необходимость знания кишков библиотек
    Капитан сложность
    Долой
    инверсию
    контроля!
    165

    View full-size slide

  163. Проблемы
    Толстый сервис
    1. Необходимость знания кишков библиотек
    2. Лишние куски кода в самом сервисе
    3. Случайное подхваченные бины
    166

    View full-size slide

  164. Не в SOAP дело
    ● Thrift/gRPC
    ● Netty
    ● Любая сложная или устаревшая внешняя зависимость
    167

    View full-size slide

  165. Сложность конфигурации
    библиотеки сопоставима со
    сложностью логики библиотеки
    Даешь инверсию контроля не только для компонентов Spring!

    View full-size slide

  166. Умным сервисам - умные библиотеки
    169

    View full-size slide

  167. А какие ещё стартеры бывают?
    ● Tracing
    ● Logging
    ● Health indicators
    ● Monitoring
    ● Etc
    170

    View full-size slide

  168. А какие ещё стартеры бывают?
    ● Tracing
    ● Logging
    ● Health indicators
    ● Monitoring
    ● Etc
    ● Какие-то ваши стартеры
    171

    View full-size slide

  169. Какие-то ваши стартеры
    172

    View full-size slide

  170. Какие-то ваши стартеры
    173

    View full-size slide

  171. Какие-то ваши стартеры
    174

    View full-size slide

  172. Какие ещё
    стартеры???
    175

    View full-size slide

  173. Стандартного набора
    хватит всем!
    Зачем писать свое?
    Опытный тех. лид
    176

    View full-size slide

  174. Стандартного набора
    хватит всем!
    Зачем писать свое?
    И как тестировать?
    Опытный тех. лид
    177

    View full-size slide

  175. Э не не не. Нам нужны свои
    178

    View full-size slide

  176. Э не не не. Нам нужны свои
    1. Не для всего есть стартеры
    2. Мы можем их тестировать
    179

    View full-size slide

  177. Э не не не. Нам нужны свои
    180

    View full-size slide

  178. Не все есть – ок
    А тестировать как
    181

    View full-size slide

  179. ● ApplicationContextRunner
    ● @SpringBootTest
    ● Всё остальное тестируется как обычный spring код
    Spring Boot Test
    182

    View full-size slide

  180. Структура
    +-- starter
    +--- autoconfigure
    +--- starter
    \--- examples
    +-- demo-spec-0
    +-- demo-spec-1
    \-- demo-spec-N
    183

    View full-size slide

  181. Структура
    +-- starter
    +--- autoconfigure
    +--- starter
    \--- examples
    +-- demo-spec-0
    +-- demo-spec-1
    \-- demo-spec-N
    + spec code
    + tests
    184

    View full-size slide

  182. Структура
    +-- starter
    +--- autoconfigure
    +--- starter
    \--- examples
    +-- demo-spec-0
    +-- demo-spec-1
    \-- demo-spec-N
    + spec code
    + tests
    185

    View full-size slide

  183. Структура
    +-- starter
    +--- autoconfigure
    +--- starter
    \--- examples
    +-- demo-spec-0
    +-- demo-spec-1
    \-- demo-spec-N
    + spec code
    + tests
    186

    View full-size slide

  184. Структура
    +-- starter
    +--- autoconfigure
    +--- starter
    \--- examples
    +-- demo-spec-0
    +-- demo-spec-1
    \-- demo-spec-N
    + spec code
    + tests
    187

    View full-size slide

  185. Да чё там тестировать то
    Unit Тесты
    пиши и всё,
    да?
    188

    View full-size slide

  186. Первое использование
    189

    View full-size slide

  187. Failed to load ApplicationContext
    Caused by:
    org.springframework.beans.factory.BeanDefinitionStoreException:
    Invalid bean definition with name 'ru.some.pack.client.SomeClient' defined
    in null: Could not resolve placeholder some.url' in value
    "http://${some.url}"; nested exception is
    java.lang.IllegalArgumentException: Could not resolve placeholder some.url'
    in value "http://${some.url}"
    Caused by:
    java.lang.IllegalArgumentException: Could not resolve placeholder
    some.url' in value "http://${some.url}"
    Первое использование
    190

    View full-size slide

  188. starter/autoconfigure — tests
    Unit — per class
    191

    View full-size slide

  189. starter/autoconfigure — tests
    Unit — per class
    Component — per functionality/per spec
    192

    View full-size slide

  190. Starter component tests
    Сформировать часть контекста нам помогут:
    1. @SpringBootTest
    2. @TestConfiguration
    3. @ContextConfiguration
    4. ApplicationContextRunner
    193

    View full-size slide

  191. @SpringBootTest
    @SpringBootTest(classes = [ContextPartConfiguration])
    class CxfConnectionTimeoutSpec extends Specification {

    }
    194

    View full-size slide

  192. @SpringBootTest
    @SpringBootTest(classes = [ContextPartConfiguration])
    class CxfConnectionTimeoutSpec extends Specification {
    @Requires({ !os.isMacOs() })
    def 'should apply timeout to ASYNC requests'() {
    when:
    client.sayHelloAsync('foo', { res -> }).get()
    then:
    ExecutionException ex = thrown()
    ex.cause.class == SocketTimeoutException
    }
    ... 195

    View full-size slide

  193. @SpringBootTest
    @SpringBootTest(classes = [ContextPartConfiguration])
    class CxfConnectionTimeoutSpec extends Specification {
    ...
    @Requires({ os.isMacOs() })
    def 'should apply timeout to ASYNC requests for OSX'() {
    when:
    client.sayHelloAsync('foo', { res -> }).get()
    then:
    ExecutionException ex = thrown()
    ex.cause.class == ConnectException
    } 196

    View full-size slide

  194. @ContextConfiguration
    @ContextConfiguration(classes = ValidConfiguration)
    class InterceptorConfigurerTest extends Specification {
    @Autowired
    CxfInterceptorConfigurer interceptorConfigurer
    def "should add interceptors to JaxWsProxyFactoryBean"() {
    when:
    interceptorConfigurer.configure(...)
    then:
    ...
    }
    } 197

    View full-size slide

  195. ApplicationContextRunner
    new ApplicationContextRunner()
    .withConfiguration(AutoConfigurations.of(
    PropertyPlaceholderAutoConfiguration,
    CxfClientAutoConfiguration
    ))
    .withUserConfiguration(ExampleCxfConfiguration.class)
    .withPropertyValues(*(CXF_ALL_CLIENTS_VARARG+'spring.cxf.useAnyBea
    nAsDefaultSslContext=true'))
    198

    View full-size slide

  196. Псс, код посмотреть
    хочешь?

    View full-size slide

  197. Подробнее – смотри доклад
    Spring Boot Test
    https://www.youtube.com/watch?v=7mZqJShu_3c

    View full-size slide

  198. Мы готовы писать свой стартер!
    Новичок #1
    Новичок #2 Новичок #3
    Новичок #4
    Странный
    новичок
    201

    View full-size slide

  199. Прошло еще полгода
    202

    View full-size slide

  200. Вася, обнови стартер
    Но везде сразу!
    Опытный тех. лид
    203

    View full-size slide

  201. Есть три пути
    Суровое настоящее
    CI/CD путь
    204

    View full-size slide

  202. Есть три пути
    Альтернативное Будущее
    Хакерский путь
    Суровое настоящее
    CI/CD путь
    205

    View full-size slide

  203. Есть три пути
    Далёкое Будущее
    Инфраструктурный путь
    Альтернативное Будущее
    Хакерский путь
    Суровое настоящее
    CI/CD путь
    206

    View full-size slide

  204. Инфраструктурный путь
    Далёкое будущее
    207

    View full-size slide

  205. Далекое будущее... или не очень
    208

    View full-size slide

  206. Далекое будущее... или не очень
    K U B E R N E T E S
    209

    View full-size slide

  207. Далекое будущее... или не очень
    K U B E R N E T E S S I D E C A R
    210

    View full-size slide

  208. Kubernetes Sidecar
    POD
    Application
    container
    Sidecar
    container
    211

    View full-size slide

  209. Kubernetes Sidecar
    POD
    Application
    container
    Sidecar
    container
    Могут быть:
    212

    View full-size slide

  210. Kubernetes Sidecar
    POD
    Application
    container
    Sidecar
    container
    Могут быть:
    ● общая файловая
    система
    ● общая сеть
    213

    View full-size slide

  211. Kubernetes Sidecar
    POD
    APP
    container
    Logs
    Sidecar
    Proxy
    Sidecar
    Something
    Sidecar
    214

    View full-size slide

  212. Не везде работает
    ● Tracing покрывается не до конца - коннекты к БД и MQ не
    обслуживаются
    215

    View full-size slide

  213. Не везде работает
    ● Tracing покрывается не до конца - коннекты к БД и MQ не
    обслуживаются
    ● Логи покрываются не до конца - приложение в любом случае должно
    выдавать структурированный лог
    216

    View full-size slide

  214. Хакерский путь
    Альтернативное будущее
    217

    View full-size slide

  215. Просто контейнеры
    218

    View full-size slide

  216. Просто контейнеры
    219

    View full-size slide

  217. Просто контейнеры
    Любой оркестратор:
    ● Kubernetes
    ● Mesos
    ● Swarm
    ● Bash + puppet
    ● Что угодно
    запускающее
    контейнер на хосте
    220

    View full-size slide

  218. Cloudfoundry buildpacks
    221

    View full-size slide

  219. Cloudfoundry buildpacks
    Buildpack
    Scripts
    Filesystem droplet
    additional libs/starter/files
    222

    View full-size slide

  220. Cloudfoundry buildpacks
    Container APP
    Buildpack
    Scripts
    Filesystem
    droplet
    223

    View full-size slide

  221. Cloudfoundry buildpacks
    Container
    APP
    with
    classpath
    additional
    jobs
    224

    View full-size slide

  222. Любые контейнеры
    Container Base Image
    225

    View full-size slide

  223. Любые контейнеры
    Container Base Image
    additional
    libs/starter/files
    226

    View full-size slide

  224. Любые контейнеры
    Container Base Image
    additional
    libs/starter/files
    java -cp"app.jar:lib/*"
    227

    View full-size slide

  225. CI/CD путь обновления
    Суровое настоящее
    228

    View full-size slide

  226. А что обновляем то?
    229

    View full-size slide

  227. Подопытный CI/CD
    N сервисов
    230

    View full-size slide

  228. Подопытный CI/CD
    N сервисов
    M стартеров 231

    View full-size slide

  229. Подопытный CI/CD
    N сервисов
    M стартеров 232

    View full-size slide

  230. Подопытный CI/CD
    N сервисов
    M стартеров
    N сервисов
    с M стартерами
    233

    View full-size slide

  231. Подопытный CI/CD
    build
    rebuild
    rebuild
    rebuild
    rebuild
    rebuild
    rebuild
    234

    View full-size slide

  232. rebuild
    rebuild
    rebuild
    rebuild
    rebuild
    rebuild
    Подопытный CI/CD
    235

    View full-size slide

  233. rebuild
    rebuild
    rebuild
    rebuild
    rebuild
    rebuild
    Подопытный CI/CD
    Deploy ALL
    236

    View full-size slide

  234. rebuild
    rebuild
    rebuild
    rebuild
    rebuild
    rebuild
    Подопытный CI/CD
    Deploy ALL
    production
    237

    View full-size slide

  235. А какие стартеры будем
    вставлять
    238

    View full-size slide

  236. Стартеры тоже бывают разные
    Starter#1 Starter#2 Starter#3 spring-boot-autoconfigure
    239

    View full-size slide

  237. В чем разница?
    Starter#1
    Starter#2
    Starter#3
    240

    View full-size slide

  238. В чем разница?
    Starter#1
    Starter#2
    Starter#3
    spring-boot-autoconfigure
    241

    View full-size slide

  239. Подход к снаряду №1
    Наивный

    View full-size slide

  240. Добавляем стартеры
    transactions-api/build.gradle:
    dependencies {
    compile 'hazelcast-starter:1.0.0'
    compile 'redis-starter:0.2.0'
    compile 'mongodb-starter:0.2.0'

    }
    243

    View full-size slide

  241. Добавляем стартеры
    transactions-api/build.gradle:
    dependencies {
    compile 'hazelcast-starter:1.0.0'
    compile 'redis-starter:0.2.0'
    compile 'mongodb-starter:0.2.0'

    }
    // → 'hazelcast:3.6.9'
    // → 'redis:1.1.1'
    // → 'mongodb:3.6.0'
    Транзитивные
    зависимости
    244

    View full-size slide

  242. Добавляем стартеры
    Проблему
    видишь?
    245

    View full-size slide

  243. Добавляем стартеры
    Hazelcast Cluster
    v2.x.x
    Hazelcast Client
    v3.x.x
    +--- hazelcast-starter:1.0.0
    \--- hazelcast:3.6.6
    246

    View full-size slide

  244. Gradle
    transactions-api:
    dependencies {
    compile 'hazelcast:3.6.9'
    compile 'redis:1.1.1'
    compile 'mongodb:3.6.0'
    compile 'hazelcast-starter:1.0.0'
    compile 'redis-starter:0.2.0'
    compile 'mongodb-starter:0.2.0'

    }
    247

    View full-size slide

  245. Gradle
    transactions-api:
    dependencies {
    compile 'hazelcast:3.6.9'
    compile 'redis:1.1.1'
    compile 'mongodb:3.6.0'
    compile 'hazelcast-starter:1.0.0'
    compile 'redis-starter:0.2.0'
    compile 'mongodb-starter:0.2.0'

    }
    transactions-api:
    dependencies {
    compile 'hazelcast:3.6.9'
    compile 'redis:1.1.1'
    compile 'mongodb:3.6.0'
    compile 'fat-starter:100.50.0'
    }
    248

    View full-size slide

  246. Gradle
    transactions-api:
    dependencies {
    compile 'hazelcast:3.6.9'
    compile 'redis:1.1.1'
    compile 'mongodb:3.6.0'
    compile 'hazelcast-starter:1.0.0'
    compile 'redis-starter:0.2.0'
    compile 'mongodb-starter:0.2.0'

    }
    transactions-api:
    dependencies {
    compile 'hazelcast:3.6.9'
    compile 'redis:1.1.1'
    compile 'mongodb:3.6.0'
    compile 'fat-starter:100.50.0'
    }
    249

    View full-size slide

  247. Толстеем
    250

    View full-size slide

  248. Толстеем, Худеем
    251

    View full-size slide

  249. Толстеем, Худеем, Толстеем
    252

    View full-size slide

  250. Gradle
    transactions-api:
    dependencies {
    compile …
    compile …
    }
    offers-api:
    dependencies {
    compile …
    compile …
    }
    ...
    253

    View full-size slide

  251. Gradle
    transactions-api:
    dependencies {
    compile …
    compile …
    }
    offers-api:
    dependencies {
    compile …
    compile …
    }
    ...
    accounts-api:
    dependencies {
    compile …
    compile …
    }
    settings-api:
    dependencies {
    compile …
    compile …
    }
    ...
    transfer-api:
    dependencies {
    compile …
    compile …
    }
    payment-api:
    dependencies {
    compile …
    compile …
    }
    ...
    254

    View full-size slide

  252. Gradle
    transactions-api:
    dependencies {
    compile …
    compile …
    }
    offers-api:
    dependencies {
    compile …
    compile …
    }
    ...
    accounts-api:
    dependencies {
    compile …
    compile …
    }
    settings-api:
    dependencies {
    compile …
    compile …
    }
    ...
    transfer-api:
    dependencies {
    compile …
    compile …
    }
    payment-api:
    dependencies {
    compile …
    compile …
    }
    ...
    Captain
    Copy-Paste
    255

    View full-size slide

  253. Все немного разные
    256

    View full-size slide

  254. 'hazelcast:3.6.9'
    'redis:1.1.1'
    Указываем версии
    257

    View full-size slide

  255. 'hazelcast:3.6.9'
    'redis:1.1.1'
    Указываем версии
    'hazelcast:3.6.9'
    'redis:1.1.1'
    'mongodb:3.6.0'
    258

    View full-size slide

  256. 'hazelcast:3.6.9'
    'redis:1.1.1'
    Указываем версии
    'hazelcast:3.6.9'
    'redis:1.1.1'
    'mongodb:3.6.0'
    'hazelcast:3.6.9'
    'redis:1.1.1'
    'mongodb:3.6.0'
    'hazelcast-starter:1.0.0'
    'redis-starter:0.2.0'
    'mongodb-starter:0.2.0'
    259

    View full-size slide

  257. 'hazelcast:3.6.9'
    'redis:1.1.1'
    Указываем версии
    'hazelcast:3.6.9'
    'redis:1.1.1'
    'mongodb:3.6.0'
    'hazelcast:3.6.9'
    'redis:1.1.1'
    'mongodb:3.6.0'
    'hazelcast-starter:1.0.0'
    'redis-starter:0.2.0'
    'mongodb-starter:0.2.0'
    Ну такое..
    260

    View full-size slide

  258. 'hazelcast:3.6.9'
    'redis:1.1.1'
    Указываем версии
    'hazelcast:3.6.9'
    'redis:1.1.1'
    'mongodb:3.6.0'
    'hazelcast:3.6.9'
    'redis:1.1.1'
    'mongodb:3.6.0'
    'hazelcast-starter:1.0.0'
    'redis-starter:0.2.0'
    'mongodb-starter:0.2.0'
    Ну такое..
    Буду складывать jar`ы
    в VCS
    261

    View full-size slide

  259. Все немного разные
    'hazelcast:3.6.9'
    'redis:1.1.1'
    'mongodb:3.6.0'
    'hazelcast-starter:1.0.0'
    'redis-starter:0.2.0'
    'mongodb-starter:0.2.0'
    'elasticsearch-starter:1.2.0
    'mesos-starter:0.1.0'
    'arangodb-starter:0.2.0'
    'eureka-starter:1.8.3'
    'sleuth-starter:1.0.8'
    'zipkin-starter:3.1.1'
    'jcache-starter:2.4.1'
    'actuator-starter:0.1.0'
    'aop-starter:0.2.0'
    'logging-starter:1.8.3'
    'freemarker-starter:1.0.8'
    'validation-starter:3.1.1'
    'tomcat-starter:3.1.1'
    'etc-starter:0.1.0' 262

    View full-size slide

  260. Все немного разные
    'hazelcast:3.6.9'
    'redis:1.1.1'
    'mongodb:3.6.0'
    'hazelcast-starter:1.0.0'
    'redis-starter:0.2.0'
    'mongodb-starter:0.2.0'
    'elasticsearch-starter:1.2.0
    'mesos-starter:0.1.0'
    'arangodb-starter:0.2.0'
    'eureka-starter:1.8.3'
    'sleuth-starter:1.0.8'
    'zipkin-starter:3.1.1'
    'jcache-starter:2.4.1'
    'actuator-starter:0.1.0'
    'aop-starter:0.2.0'
    'logging-starter:1.8.3'
    'freemarker-starter:1.0.8'
    'validation-starter:3.1.1'
    'tomcat-starter:3.1.1'
    'etc-starter:0.1.0' 263

    View full-size slide

  261. Все немного разные
    'hazelcast:3.6.9'
    'redis:1.1.1'
    'mongodb:3.6.0'
    'hazelcast-starter:1.0.0'
    'redis-starter:0.2.0'
    'mongodb-starter:0.2.0'
    'elasticsearch-starter:1.2.0
    'mesos-starter:0.1.0'
    'arangodb-starter:0.2.0'
    'eureka-starter:1.8.3'
    'sleuth-starter:1.0.8'
    'zipkin-starter:3.1.1'
    'jcache-starter:2.4.1'
    'actuator-starter:0.1.0'
    'aop-starter:0.2.0'
    'logging-starter:1.8.3'
    'freemarker-starter:1.0.8'
    'validation-starter:3.1.1'
    'tomcat-starter:3.1.1'
    'etc-starter:0.1.0' 264

    View full-size slide

  262. Все немного разные
    'hazelcast:3.6.9'
    'redis:1.1.1'
    'mongodb:3.6.0'
    'hazelcast-starter:1.0.0'
    'redis-starter:0.2.0'
    'mongodb-starter:0.2.0'
    'elasticsearch-starter:1.2.0
    'mesos-starter:0.1.0'
    'arangodb-starter:0.2.0'
    'eureka-starter:1.8.3'
    'sleuth-starter:1.0.8'
    'zipkin-starter:3.1.1'
    'jcache-starter:2.4.1'
    'actuator-starter:0.1.0'
    'aop-starter:0.2.0'
    'logging-starter:1.8.3'
    'freemarker-starter:1.0.8'
    'validation-starter:3.1.1'
    'tomcat-starter:3.1.1'
    'etc-starter:0.1.0' 265

    View full-size slide

  263. Все немного разные
    'hazelcast:3.6.9'
    'redis:1.1.1'
    'mongodb:3.6.0'
    'hazelcast-starter:1.0.0'
    'redis-starter:0.2.0'
    'mongodb-starter:0.2.0'
    'elasticsearch-starter:1.2.0
    'mesos-starter:0.1.0'
    'arangodb-starter:0.2.0'
    'eureka-starter:1.8.3'
    'sleuth-starter:1.0.8'
    'zipkin-starter:3.1.1'
    'jcache-starter:2.4.1'
    'actuator-starter:0.1.0'
    'aop-starter:0.2.0'
    'logging-starter:1.8.3'
    'freemarker-starter:1.0.8'
    'validation-starter:3.1.1'
    'tomcat-starter:3.1.1'
    'etc-starter:0.1.0' 266

    View full-size slide

  264. Все немного разные
    'hazelcast:3.6.9'
    'redis:1.1.1'
    'mongodb:3.6.0'
    'hazelcast-starter:1.0.0'
    'redis-starter:0.2.0'
    'mongodb-starter:0.2.0'
    'elasticsearch-starter:1.2.0
    'mesos-starter:0.1.0'
    'arangodb-starter:0.2.0'
    'eureka-starter:1.8.3'
    'sleuth-starter:1.0.8'
    'zipkin-starter:3.1.1'
    'jcache-starter:2.4.1'
    'actuator-starter:0.1.0'
    'aop-starter:0.2.0'
    'logging-starter:1.8.3'
    'freemarker-starter:1.0.8'
    'validation-starter:3.1.1'
    'tomcat-starter:3.1.1'
    'etc-starter:0.1.0' 267

    View full-size slide

  265. Все немного разные
    'hazelcast:3.6.9'
    'redis:1.1.1'
    'mongodb:3.6.0'
    'hazelcast-starter:1.0.0'
    'redis-starter:0.2.0'
    'mongodb-starter:0.2.0'
    'elasticsearch-starter:1.2.0
    'mesos-starter:0.1.0'
    'arangodb-starter:0.2.0'
    'eureka-starter:1.8.3'
    'sleuth-starter:1.0.8'
    'zipkin-starter:3.1.1'
    'jcache-starter:2.4.1'
    'actuator-starter:0.1.0'
    'aop-starter:0.2.0'
    'logging-starter:1.8.3'
    'freemarker-starter:1.0.8'
    'validation-starter:3.1.1'
    'tomcat-starter:3.1.1'
    'etc-starter:0.1.0' 268

    View full-size slide

  266. Сложно обновлять зависимости
    Все немного разные
    269

    View full-size slide

  267. Выход №1 – latest version
    dependencies {
    implementation 'some-starter:0.1.0' // → 'some-starter:+'
    implementation 'marathon-starter:0.1.0' // → 'marathon-starter:+'
    ...
    }
    270

    View full-size slide

  268. Астанавитесь
    271

    View full-size slide

  269. Выход №1 – latest version + locking
    dependencyLocking {
    lockAllConfigurations()
    }
    dependencies {
    implementation 'some-starter:0.1.0' // → 'some-starter:+'
    implementation 'marathon-starter:0.1.0' // → 'marathon-starter:+'
    ...
    }
    272

    View full-size slide

  270. Выход №1 – latest version + locking
    $ ./gradlew build --write-locks
    273

    View full-size slide

  271. $ ./gradlew build --write-locks
    $ ./gradlew build --update-locks ru.company:starter
    Выход №1 – latest version + locking
    274

    View full-size slide

  272. Выход №1 – latest version + locking
    $ ./gradlew build --write-locks
    $ ./gradlew build --update-locks ru.company:starter
    $ git status
    modified: gradle/dependency-locks/annotationProcessor.lockfile
    modified: gradle/dependency-locks/buildscript-classpath.lockfile
    modified: gradle/dependency-locks/compileClasspath.lockfile
    modified: gradle/dependency-locks/runtimeClasspath.lockfile
    modified: gradle/dependency-locks/testAnnotationProcessor.lockfile
    modified: gradle/dependency-locks/testCompileClasspath.lockfile
    modified: gradle/dependency-locks/testRuntimeClasspath.lockfile
    275

    View full-size slide

  273. Выход №1 – latest version + locking
    diff ./gradle/dependency-locks/buildscript-classpath.lockfile:
    -com.netflix.nebula:nebula-publishing-plugin:11.0.0
    -com.netflix.nebula:nebula-release-plugin:10.1.1
    +com.netflix.nebula:nebula-publishing-plugin:12.0.0
    +com.netflix.nebula:nebula-release-plugin:10.1.2
    276

    View full-size slide

  274. rebuild
    rebuild
    rebuild
    rebuild
    rebuild
    rebuild
    Выход №1 – latest version + locking
    update-lock
    277

    View full-size slide

  275. rebuild
    rebuild
    rebuild
    rebuild
    rebuild
    rebuild
    Выход №1 – latest version + locking
    update-lock
    278

    View full-size slide

  276. rebuild
    rebuild
    rebuild
    rebuild
    rebuild
    rebuild
    Выход №1 – latest version + locking
    update-lock
    279

    View full-size slide

  277. – Но это нужно
    Тестить!
    280

    View full-size slide

  278. Пример
    Инф
    раструктура
    Хей, у нас новые новая система
    метрик!
    281

    View full-size slide

  279. Хей, у нас новые новая система
    метрик!
    Пример
    Инф
    раструктура
    Но я не умею экспортировать
    метрики в таком формате
    282

    View full-size slide

  280. Хей, у нас новые новая система
    метрик!
    Пример
    Но я не умею экспортировать
    метрики в таком формате
    Инф
    раструктура Ща мы тебя пересоберём
    283

    View full-size slide

  281. Ща мы тебя пересобирём
    Пример
    Инф
    раструктура
    284

    View full-size slide

  282. Ща мы тебя пересобирём
    Пример
    Инф
    раструктура
    ну ок...
    285

    View full-size slide

  283. Ща мы тебя пересобирём
    Пример
    Инф
    раструктура
    Теперь я умею экспортироавть
    Метрики в нужном формате
    286

    View full-size slide

  284. Ща мы тебя пересобирём
    Теперь я умею экспортироавть
    Метрики в нужном формате
    Пример
    Инф
    раструктура Ща мы тебя задеплоим!
    287

    View full-size slide

  285. Ща мы тебя пересобирём
    Теперь я умею экспортироавть
    Метрики в нужном формате
    Пример
    Инф
    раструктура Ща мы тебя задеплоим!
    288

    View full-size slide

  286. Выход №2 – Release Train
    dependencies {
    implementation 'my-company-uber-jar:0.1.0.RELEASE_TRAIN_0'
    ...
    }
    289

    View full-size slide

  287. Выход №2 – Release Train
    290

    View full-size slide

  288. rebuild
    rebuild
    rebuild
    rebuild
    rebuild
    rebuild
    Подопытный CI/CD
    update?
    291

    View full-size slide

  289. Управляем
    сборкой
    Выход №3 – комплексный билд
    292

    View full-size slide

  290. Управляем
    сборкой,
    полностью
    Выход №3 – комплексный билд
    293

    View full-size slide

  291. build.gradle:
    apply plugin: "version.plugin"
    apply plugin: "maven.plugin"
    apply plugin: "check.plugin"
    apply plugin: "findbugs.plugin"
    apply plugin: "verify.plugin"
    apply plugin: "publish.plugin"
    apply plugin: "awesome.plugin"
    294
    Декларативный подход

    View full-size slide


  292. class MyPlugin implements Plugin {
    void apply(Project project) {
    project.configure {
    dependencies {
    compile …
    compile …
    }
    }
    }
    }
    Сила в композиции
    295

    View full-size slide

  293. Где достать зависимости?
    Application
    296

    View full-size slide

  294. Gradle знает
    Gradle plugin
    Application
    297

    View full-size slide

  295. Gradle знает где их искать
    Gradle plugin
    Application
    298

    View full-size slide

  296. Немножко магии
    Gradle plugin
    Application
    299

    View full-size slide

  297. Инверсия контроля для
    зависимостей
    ug
    Application
    Redis starter HZ starter Mongo starter
    300

    View full-size slide

  298. Почему не хватает BOM?
    301

    View full-size slide

  299. Почему не хватает BOM?
    dependencies {
    gems 'asciidoctor-diagram:1.5.4.1'
    }
    asciidoctorj { version = '1.5.6' }
    task cleanTempDirs(type: Delete) {
    delete fileTree(dir: docsDir)
    }
    artifactoryPublish {
    properties = [artifactType: 'DOC']
    }
    asciidoctor {
    finalizedBy tasks.withType(Zip)
    sources {
    include fileTree(dir: 'src/docs', includ
    include fileTree(dir: snippetsDir, inclu
    }
    dependsOn jrubyPrepare, project(':app').test
    gemPath = jrubyPrepare.outputDir
    requires = ['asciidoctor-diagram']
    attributes 'source-highlighter': 'prettify',
    'imagesdir': 'images',
    'toc': 'left',
    'icons': 'font',
    ...~200 lines 302

    View full-size slide

  300. Почему не хватает BOM?
    dependencies {
    gems 'asciidoctor-diagram:1.5.4.1'
    }
    asciidoctorj { version = '1.5.6' }
    task cleanTempDirs(type: Delete) {
    delete fileTree(dir: docsDir)
    }
    artifactoryPublish {
    properties = [artifactType: 'DOC']
    }
    asciidoctor {
    finalizedBy tasks.withType(Zip)
    sources {
    include fileTree(dir: 'src/docs', includ
    include fileTree(dir: snippetsDir, inclu
    }
    dependsOn jrubyPrepare, project(':app').test
    gemPath = jrubyPrepare.outputDir
    requires = ['asciidoctor-diagram']
    attributes 'source-highlighter': 'prettify',
    'imagesdir': 'images',
    'toc': 'left',
    'icons': 'font',
    ...~200 lines
    ugin
    303

    View full-size slide


  301. class MyPlugin implements Plugin {
    void apply(Project project) {
    project.configure {
    dependencies {
    compile …
    compile …
    }
    }
    project.plugins.apply(AddGitTagPlugin)
    project.plugins.apply(UserInfoPlugin)
    }
    }
    Сила в композиции
    304

    View full-size slide


  302. class MyPlugin implements Plugin {
    void apply(Project project) {
    project.configure {
    dependencies {
    compile …
    compile …
    }
    }
    project.plugins.apply(AddGitTagPlugin)
    project.plugins.apply(UserInfoPlugin)
    project.tasks.withType(SomeTaskType) { //configure
    }
    }
    }
    305
    Сила в композиции

    View full-size slide

  303. Сила в композиции
    apply plugin: "your.plugin.all" //2.1.+
    306

    View full-size slide

  304. Сила в композиции
    apply plugin: "your.plugin.all" //2.1.+
    307
    Автоапдейт минорных версий
    Путь героев – но это уже другая история

    View full-size slide

  305. Сила в композиции
    apply plugin: "your.plugin.all" //2.1.+
    308
    Автоапдейт минорных версий
    Путь героев – но это уже другая история
    И dependency locking тоже
    работает!

    View full-size slide

  306. Dependency Lock для плагинов
    buildscript {
    configurations.classpath {
    resolutionStrategy.activateDependencyLocking()
    }
    }
    309

    View full-size slide

  307. На больших проектах нужна инверсия контроля для
    сборки и зависимостей
    Идея
    Gradle plugin
    310

    View full-size slide

  308. И нет никаких проблем?
    311

    View full-size slide

  309. Как это работает
    starter
    Gradle plugin
    Любое изменение – повод пересобрать всё и
    передеплоить
    dependency
    312

    View full-size slide

  310. Как это работает
    build
    rebuild
    rebuild
    rebuild
    rebuild
    rebuild
    rebuild
    Обновление
    приводит к сборке
    новой версии
    сервисов
    dependency
    313

    View full-size slide

  311. rebuild
    rebuild
    rebuild
    rebuild
    rebuild
    rebuild
    Как это работает
    Deploy ALL
    production
    И последующему
    деплою
    314

    View full-size slide

  312. rebuild
    rebuild
    rebuild
    rebuild
    rebuild
    rebuild
    Как это работает
    Deploy ALL
    production
    И последующему
    деплою
    315

    View full-size slide

  313. rebuild
    rebuild
    rebuild
    rebuild
    rebuild
    rebuild
    Как это работает
    Deploy ALL
    test,dev,prod
    И последующему
    деплою и
    тестированию
    316

    View full-size slide

  314. Систему свою не сегментируй
    Если начал обновление – закончи его до конца

    View full-size slide

  315. Актуализация версий
    Ручное
    + понятно
    + стабильно
    - геморойно
    - сложно
    масштабировать
    - нет контроля
    запуска
    - ...
    CI/CD
    + единый процесс для
    всех
    + стабильно
    - много работы
    - цементирует
    процессы
    - СI/CD — 24/7
    - ...
    Runtime
    + Всё из CI/CD
    + без пересборки
    + быстрый запуск
    + полный контроль
    - очень много работы
    - опасно
    - сложно тестировать
    - ...
    318

    View full-size slide

  316. Вася, обнови уже этот
    стартер
    Долго обновляется
    Понапихают всякого
    Опытный тех. лид
    319

    View full-size slide

  317. Сколько это займет?
    320

    View full-size slide

  318. Сколько это займет?
    100 сервисов
    по 3 инстанса
    321

    View full-size slide

  319. Сколько это займет?
    100 сервисов
    по 3 инстанса
    Каждый рестартует
    за ??? сек
    322

    View full-size slide

  320. Сколько это займет?
    100 X 3 X 60 = ???
    323

    View full-size slide

  321. Прошло 5 часов
    324

    View full-size slide

  322. Оптимизация Можно же
    параллели...
    325

    View full-size slide

  323. Update strategy
    ● Скачать и поднять новый инстанс
    ● Дождаться пока инстанс запустится
    ● Проверить что он жив
    ● Переключить балансировку
    ● Потушить старый инстанс
    326

    View full-size slide

  324. Update strategy
    ● Скачать и поднять новый инстанс
    ● Дождаться пока инстанс запустится
    ● Проверить что он жив
    ● Переключить балансировку
    ● Потушить старый инстанс
    327

    View full-size slide

  325. Похудел и накачался, но тормоз
    328

    View full-size slide

  326. На что тратится время при старте?
    329

    View full-size slide

  327. На что тратится время при старте?
    ● Старт jvm
    ● Загрузка классов
    ● ???
    330

    View full-size slide

  328. Что делает Spring?
    @ComponentScan
    @Service
    @Component
    331

    View full-size slide

  329. Что нового в Spring 5?
    Context Indexer
    332

    View full-size slide

  330. Просто добавь зависимость
    dependencies {
    compileOnly 'org.springframework:spring-context-indexer:5.0.1.RELEASE'
    }
    333

    View full-size slide

  331. Просто добавь зависимость
    dependencies {
    compileOnly 'org.springframework:spring-context-indexer:5.0.1.RELEASE'
    }
    # META-INF/spring.components
    o.s.t.f.APIVersionServerFilter=org.springframework.stereotype.Component
    o.s.t.f.APIVersionFilterHelper=org.springframework.stereotype.Component
    ...
    334

    View full-size slide

  332. Просто добавь зависимость
    dependencies {
    compileOnly 'org.springframework:spring-context-indexer:5.0.1.RELEASE'
    }
    # META-INF/spring.components
    o.s.t.f.APIVersionServerFilter=org.springframework.stereotype.Component
    o.s.t.f.APIVersionFilterHelper=org.springframework.stereotype.Component
    ...
    Классы проаннотированные
    аннотацией Spring`а 335

    View full-size slide

  333. Просто добавь зависимость
    dependencies {
    compileOnly 'org.springframework:spring-context-indexer:5.0.1.RELEASE'
    }
    # META-INF/spring.components
    o.s.t.f.APIVersionServerFilter=org.springframework.stereotype.Component
    o.s.t.f.APIVersionFilterHelper=org.springframework.stereotype.Component
    ...
    Чем проаннотировано
    336

    View full-size slide

  334. И результат...
    Чёт как-то не
    сильно
    ускорилось..
    337

    View full-size slide

  335. Не там копаем
    indexer
    Я старался, но у
    тебя бинов не
    так много
    338

    View full-size slide

  336. Радикальный путь
    К черту ваш Spring,
    у меня новый друг
    TEAM LEAD MICRONAUT
    Я сделан по новым
    принципам
    339

    View full-size slide

  337. Новый подход
    MICRONAUT
    ● AST-трансформации для Groovy
    ● Annotation Processor для Java/Kotlin
    340

    View full-size slide

  338. Новый подход
    MICRONAUT
    Micronaut делает IoC/DI в во время
    компиляции
    Я быстрее, потому
    что делаю все
    заранее
    341

    View full-size slide

  339. Новый подход на Spring
    Spring Fu
    Надо просто
    немного изменить
    подход
    342

    View full-size slide

  340. Новый подход на Spring
    Spring Fu
    val app = application(WebApplicationType.SERVLET) {
    logging {
    level = LogLevel.DEBUG
    }
    beans {
    bean()
    }
    webMvc {
    router {
    val service = ref()
    GET("/") {
    ok().body(service.generateMessage())
    }
    }
    converters {
    string()
    jackson {
    indentOutput = true 343

    View full-size slide

  341. название →__
    условие →__
    -Xmx/mb время старта/ms
    -Xmx=enough
    micronaut 6 950 +- 0.04
    spring boot 11 1500 +- 0.1
    spark 3 350 +- 0.01
    spring Fu 5 1041 +- 0.08
    Сравним время старта
    344

    View full-size slide

  342. Не похоже на реальную жизнь
    Зачем мне голый
    сервис,
    где БД/MQ/Cloud???
    TEAM LEAD
    345

    View full-size slide

  343. название →__
    условие →__
    -Xmx/mb время старта/ms
    -Xmx=enough
    micronaut 19 2400
    spring boot 15 3400
    Если с mongo
    346

    View full-size slide

  344. название →__
    условие →__
    -Xmx/mb время старта/ms
    -Xmx=enough
    micronaut 15 3000
    spring boot 24 8000
    Если с DB/MQ/Cloud
    347

    View full-size slide

  345. Неужели только на DI?
    Чего он там копается??
    TEAM LEAD
    348

    View full-size slide

  346. https://github.com/dsyer/spring-boot-allocations
    349

    View full-size slide

  347. http://presos.dsyer.com/decks/how-fast-is-spring.html
    350

    View full-size slide

  348. http://presos.dsyer.com/decks/how-fast-is-spring.html
    351

    View full-size slide

  349. GraalVM - в погоне за скоростью
    - Собираем долго
    - Запускаем быстро
    352

    View full-size slide

  350. Как вам такое время старта?
    o.s.b.Spring - Started application in 120 ms
    353

    View full-size slide

  351. Spring
    Functional
    TEAM LEAD
    Micronaut
    GraalVM
    354

    View full-size slide

  352. TEAM LEAD
    Быстро, но как с этим
    жить в реальности?
    355

    View full-size slide

  353. TEAM LEAD
    Собрать не так просто
    GraalVM
    356

    View full-size slide

  354. Здравый смысл
    Куда спешим?
    Какая цель?
    357

    View full-size slide

  355. Хочу serverless… наверное
    358

    View full-size slide

  356. Хочу IoT… наверное
    359

    View full-size slide

  357. Еще варианты?
    360

    View full-size slide

  358. TEAM LEAD
    Экосистема от
    Grails и Spring
    Micronaut
    361

    View full-size slide

  359. TEAM LEAD
    Incubating и старые
    стартеры сделаны по
    старому
    Spring Fu
    362

    View full-size slide

  360. TEAM LEAD
    Может потюним
    Spring?
    Spring Boot?
    363

    View full-size slide

  361. Где оптимизировать
    ● Не забывать обновляться
    364

    View full-size slide

  362. Где оптимизировать
    ● Не забывать обновляться
    ● Следить за лишними зависимостями
    365

    View full-size slide

  363. Где оптимизировать
    ● Не забывать обновляться
    ● Следить за лишними зависимостями
    ● Следить за тем, что и как инициализируются в приложениях
    366

    View full-size slide

  364. Где оптимизировать
    ● Не забывать обновляться
    ● Следить за лишними зависимостями
    ● Следить за тем, что и как инициализируются в приложениях
    ● Если много бинов, использовать Context Indexer
    367

    View full-size slide

  365. Где оптимизировать
    ● Не забывать обновляться
    ● Следить за лишними зависимостями
    ● Следить за тем, что и как инициализируются в приложениях
    ● Если много бинов, использовать Context Indexer
    ● Использовать spring.main.lazy-initialization на свой страх [spring boot 2.2+]
    368

    View full-size slide

  366. Где оптимизировать
    ● Не забывать обновляться
    ● Следить за лишними зависимостями
    ● Следить за тем, что и как инициализируются в приложениях
    ● Если много бинов, использовать Context Indexer
    ● Использовать spring.main.lazy-initialization на свой страх [spring boot 2.2+]
    ● Отказаться от actuator
    369

    View full-size slide

  367. Эволюция
    370

    View full-size slide

  368. Spring Boot
    новые методы решения для новых проблем

    View full-size slide

  369. Новые решения
    для новых проблем
    Которые сами же себе и создаём

    View full-size slide

  370. Решения на одном уровне
    порождают проблемы на другом
    Нельзя закрыть проблемы всего стека на одном уровне

    View full-size slide

  371. Качественные решения требуют
    отличной экспертизы
    Лучше знаешь инструменты - порождаешь меньше проблем

    View full-size slide

  372. Человек —
    швейцарский нож
    Сообщество
    профессионалов
    376

    View full-size slide

  373. Это и есть DevOps
    бизнес-код, библиотеки,
    сборка, обновление,
    логи, мониторинг,
    разбор проблем,
    ….

    View full-size slide

  374. Эволюция
    378

    View full-size slide

  375. Пути в DevOps у всех разные
    379

    View full-size slide

  376. Вопросы?
    @tolkv
    @lavcraft
    @gorelikoff
    @gorelikov
    380

    View full-size slide

  377. Немного полезностей
    — JavaMentorJpointPC
    — JavaMentorHeisenbugPC
    381
    2020

    View full-size slide