Boot yourself, Spring is coming

Boot yourself, Spring is coming

Many years ago Java developers used "new" in order to create Java services. They had many handmade configurations mixed with business logic; they even were using copy-paste techniques. They wrote many lines of the same ugly code, which sometimes even worked.

Then Spring happened and things have changed… We received a lot of "magic" from Spring black box and our code became much cleaner and more simple.

And then Spring Boot happened… On the one hand, it solved thousands of problems: versions conflict, configuration issues, infrastructure's beans declarations, problems with environments, and even running or deploying applications including building jar/war… On the other hand, Spring Boot uses so much magic that mostly we come across two scenarios:

Everything is working without any effort even though nobody knows why.
Nothing is working and nobody knows why.
In this talk, we'll try to reveal at least a part of Spring Boot magic by discovering Spring Boot concepts, conventions and the way it works. And even though after this talk you will understand that there is no magic (mostly), you will enjoy Spring Boot even more, because you will be able to solve Spring Boot problems or conflicts without calling 911 (mostly).

40951719c6ca509831d5c38b764661c9?s=128

Kirill Tolkachev

April 09, 2018
Tweet

Transcript

  1. Spring Boot The Ripper

  2. @tolkv @lavcraft @jekaborisov @jeka1978

  3. За что мы не любим Spring Boot 2.0 в РФ

    private static boolean isAlpha(char ch) { return ch >= 'a' && ch <= 'z'; } .. @ConfigurationProperties
  4. ЗАБАСТОВКА БИНОВ ПОДАВЛЕНА, СИНГЛТОНЫ НЕ ВЫЙДУТ ИЗ КОНТЕЙНЕРА ДО КОНЦА

    СРОКА
  5. ЛЕНИВЫЕ СИНГЛТОНЫ МОГУТ НЕ СОЗДАВАТЬСЯ С ВЕРСИИ 4.3

  6. Application Listener-ы требуют получать дополнительные ивенты

  7. ApplicationListener Они объявили голодовку и их жизни в опасности

  8. Йорген Холлер не подписал заявление XmlBeanDefinitionReader-а об уходе на пенсию

  9. Они ещё Spring Boot-у послужат, прокомментировал он на Javaday 2016.

  10. ClassPathBeanDefinitionScanner ищет компоненты, но на находит сервисы

  11. BeanPostProcessor-ы требуют льготных условий. Spring держится лишь на нас

  12. BeanFactory изменяет Single Responsibility

  13. Теперь он выглядит вот так:

  14. Ретросперктива Bean Factory

  15. Application Listener ClassPatBeanDefinitionScanner BPP BPP Bean Factory BPP

  16. Application Listener ClassPatBeanDefinitionScanner BPP BPP Bean Factory BPP Context

  17. Application Listener ClassPatBeanDefinitionScanner BPP BPP Bean Factory BPP Context WAI

    EPP SApp ENV system prop application. yml SpringFactoriesLoader RDB CFL Starter mn,, spring.factories
  18. Spring Boot The Ripper

  19. None
  20. _Демо_

  21. Что не любит программист Думать о: 1. Зависимостях... 2. Настройках

    и конфигурациях Делать: 3. Деплоймент и запуск (тест/локально/прод)
  22. Что не любит программист Думать о: 1. Зависимостях... 2. Настройках

    и конфигурациях Делать: 3. Деплоймент и запуск (тест/локально/прод)
  23. Зависимости

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

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

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

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

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

    </dependencyManagement>
  31. Тоже самое в build.gradle dependencyManagement { imports { mavenBom 'org.springframework.cloud:spring-cloud-dependencies:Dalston.RELEASE'

    } }
  32. Какие теперь зависимости? 'org.springframework.boot:spring-boot-starter-web' 'org.springframework.boot:spring-boot-starter-data-jpa' 'com.h2database:h2'

  33. Настройки контекста

  34. Где контекс? @SpringBootApplilcation class App { public static void main(String[]

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

    args) { ApplicationContext context = SpringApplication.run(App.class,args); } }
  36. Загадочные аргументы Дано: RipperApplication.class public… main(String[] args) { SpringApplication.run(?,args); }

    1. RipperApplication.class 2. String.class 3. "context.xml" 4. new ClassPathResource("context.xml") 5. Package.getPackage("conference.spring.boot.ripper")
  37. SpringApplication.run(Object[] sources, String[] args)

  38. Загадочные аргументы Дано: RipperApplication.class public… main(String[] args) { SpringApplication.run(?,args); }

    1. RipperApplication.class 2. String.class 3. "context.xml" 4. new ClassPathResource("context.xml") 5. Package.getPackage("conference.spring.boot.ripper") Голосуем!
  39. Все верны

  40. SpringApplication.run(Object[] sources, String[] args) # APPLICATION SETTINGS (SpringApplication) spring.main.sources= #

    class name, package name, xml location spring.main.web-environment= # true/false spring.main.banner-mode=console # log/off
  41. Разрешите представиться

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

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

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

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

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

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

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

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

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

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

  52. Железный закон №1 В любой непонятной ситуации посылай ворона

  53. Может @EnableSomeStarter ?

  54. Ты еще @Import(SomeStarterConf.class) предложи сделать!

  55. Мы будем использовать spring.factories!

  56. Что за 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).
  57. Даёшь инверсию контроля для стартеров

  58. Железный закон №1.1 В любой непонятной ситуации посылай ворона

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

  60. @SpringBootApplication

  61. @SpringBootApplication → @ComponentScan → @Configuration → @EnableAutoConfiguration

  62. @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 { …
  63. @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 { …
  64. @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 {}; }
  65. @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 {}; }
  66. @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
  67. @EnableAutoConfiguration ImportSelector Boot Starter … Starter Web Starter Iron Starter

  68. ImportSelector Iron Starter Boot Starter … Starter Web Starter @EnableAutoConfiguration

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

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

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

  72. 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.\ ... …

  73. 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.\ ... ….

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

  75. Где то внутри CacheAutoConfiguration for (int i = 0; i

    < types.length; i++) { Imports[i] = CacheConfigurations.getConfigurationClass(types[i]); } return imports;
  76. CacheConfigurations private static final Map<CacheType, Class<?>> MAPPINGS; static { Map<CacheType,

    Class<?>> mappings = new HashMap<CacheType, Class<?>>(); mappings.put(CacheType.GENERIC, GenericCacheConfiguration.class); mappings.put(CacheType.EHCACHE, EhCacheCacheConfiguration.class); mappings.put(CacheType.HAZELCAST, HazelcastCacheConfiguration.class); mappings.put(CacheType.INFINISPAN, InfinispanCacheConfiguration.class); mappings.put(CacheType.JCACHE, JCacheCacheConfiguration.class); mappings.put(CacheType.COUCHBASE, CouchbaseCacheConfiguration.class); mappings.put(CacheType.REDIS, RedisCacheConfiguration.class); mappings.put(CacheType.CAFFEINE, CaffeineCacheConfiguration.class); addGuavaMapping(mappings); mappings.put(CacheType.SIMPLE, SimpleCacheConfiguration.class); mappings.put(CacheType.NONE, NoOpCacheConfiguration.class); MAPPINGS = Collections.unmodifiableMap(mappings); }
  77. Захардкодили

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

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

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

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

  82. Железный закон №1.2 Посылай ворона только в продакшене

  83. @ConditionalOnProduction — Демо

  84. Паззлер @Configuration @ConditionalOnСуроваяЗима public class UndeadArmyConfiguration { ... } @Configuration

    public class DragonIslandConfiguration { @Bean @ConditionalOnСуроваяЗима public DragonGlassFactory dragonGlassFactory() { return new DragonGlassFactory(); } ... }
  85. 1. 100 $ 2. 200 $ 3. 300 или 400

    $ 4. между 500 и 1000 $ 5. Больше 1000 $ * Спросить погоду стоит денег – 100 золотых драконов за раз * $ = золотой дракон ConditionalOnСуроваяЗима
  86. 1. 100 $ 2. 200 $ 3. 300 или 400

    $ 4. между 500 и 1000 $ 5. Больше 1000 $ * Спросить погоду стоит денег – 100 золотых драконов за раз * $ = золотой дракон @Configuration @ConditionalOnСуроваяЗима public class UndeadArmyConfiguration { ... } @Configuration public class DragonIslandConfiguration { @Bean @ConditionalOnСуроваяЗима public DragonGlassFactory dragonGlassFactory() { return new DragonGlassFactory(); } ... } ConditionalOnСуроваяЗима
  87. Правильный ответ 1. 100 $ 2. 200 $ 3. 300

    или 400 $ 4. между 500 и 1000 $ 5. Больше 1000 $
  88. Правильный ответ 1. 100 $ 2. 200 $ 3. 300

    или 400 $ 4. между 500 и 1000 $ 5. Больше 1000 $ 300 – если UndeadArmyConfiguration в стартере 400 – если UndeadArmyConfiguration в коде приложения
  89. Как это работает ?

  90. Как то так, через хитро закрученную жопу оно и работает

  91. Лечу куда хочу

  92. Железный закон №1.3 Отправлять ворона только если есть получатели 1.

    список получателей 2. без списка не летим 3. автокомплит Лететь то куда?
  93. Conditional и друзья @ConditionalOnMissingClass @ConditionalOnNotWebApplication @ConditionalOnProperty @ConditionalOnResource @ConditionalOnSingleCandidate @ConditionalOnWebApplication ...

    @ConditionalOnBean @ConditionalOnClass @ConditionalOnCloudPlatform @ConditionalOnExpression @ConditionalOnJava @ConditionalOnJndi @ConditionalOnMissingBean
  94. Железный закон №1.3 Отправлять ворона только если есть получатели 1.

    список получателей 2. без списка не летим 3. автокомплит Лететь то куда? ← application.yml ← @ConditionalOnProperty ← @ConfigurationProperty
  95. Железный закон №1.4 Отправляем ворона только если нет кастомного

  96. Conditional и друзья @ConditionalOnMissingClass @ConditionalOnNotWebApplication @ConditionalOnProperty @ConditionalOnResource @ConditionalOnSingleCandidate @ConditionalOnWebApplication ...

    @ConditionalOnBean @ConditionalOnClass @ConditionalOnCloudPlatform @ConditionalOnExpression @ConditionalOnJava @ConditionalOnJndi @ConditionalOnMissingBean
  97. Железный закон №1.4 Отправляем ворона только если нет кастомного @ConditionalOnMissingBean

  98. ConditionalOnPuzzler @Configuration public class КонфигурацияКазни { @Bean @ConditionalOnClass ({Мыло.class, Веревка.class})

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

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

  104. Железный закон №1.5 ВКЛ/ВЫКЛ ворона @ConditionalOnProperty

  105. 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; } Что если нужно изменить?
  106. OnPropertyCondition @ConditionalOnProduction @ConditionalOnProperty( name = "ворон.вкл" ) public IronBankApplicationListener applicationListener()

    { ... }
  107. OnPropertyCondition @ConditionalOnProduction @ConditionalOnProperty( name = "ворон.вкл", havingValue = "true" )

    public IronBankApplicationListener applicationListener() { ... }
  108. OnPropertyCondition @ConditionalOnProduction @ConditionalOnProperty( name = { "ворон.вкл", "зима.вкл", "старки.вкл" },

    havingValue = "true" ) public IronBankApplicationListener applicationListener() { ... }
  109. OnPropertyCondition @ConditionalOnProduction @ConditionalOnProperty( name = { "ворон.вкл", "зима.вкл", "старки.вкл" },

    havingValue = "true" ) public IronBankApplicationListener applicationListener() { ... } Не массив
  110. OnPropertyCondition @ConditionalOnProduction @ConditionalOnProperty(name = "ворон.вкл", havingValue="true") @ConditionalOnProperty(name = "зима.вкл", havingValue="true")

    @ConditionalOnProperty(name = "старки.вкл",havingValue="false") public IronBankApplicationListener applicationListener() { ... }
  111. OnPropertyCondition @ConditionalOnProduction @ConditionalOnProperty(name = "ворон.вкл", havingValue="true") @ConditionalOnProperty(name = "зима.вкл", havingValue="true")

    @ConditionalOnProperty(name = "старки.вкл",havingValue="false") public IronBankApplicationListener applicationListener() { ... } @ConditionalOnProperty Не @Repeatable
  112. AllNestedConditions && AnyNestedCondition

  113. OnPropertyCondition @Retention(RetentionPolicy.RUNTIME) @Target({ ElementType.TYPE, ElementType.METHOD }) @Conditional(CompositeCondition.class) public @interface ConditionalOnRaven

    { }
  114. OnPropertyCondition public class OnRavenCondition extends AllNestedConditions { @ConditionalOnProperty( name =

    "ворон.куда", havingValue = "false") public static class OnRavenProperty { } @ConditionalOnProperty( name = "ворон.вкл", havingValue = "true", matchIfMissing = true) public static class OnRavenEnabled { } ... }
  115. OnPropertyCondition @ConditionalOnRaven public IronBankApplicationListener applicationListener() { ... }

  116. Сейчас будет спойлер

  117. Сезон 8 – Зима Тута Кофебрейк

  118. Внимание спойлеры

  119. В 8 сезоне Железный банк изменит правила выдачи кредитов —

    Демо
  120. Железный закон №2 Без профиля - нельзя

  121. Demo ApplicationContextInitializer

  122. Environment Property sources: • systemProperties • system environment • random

    property • application.properties • … Active Profiles Default Profiles ENV system prop application.yml ...
  123. Почему бы не определить профиль автоматически?

  124. Напишем… EnvironmentPostProcessor EPP

  125. demo

  126. ApplicationListener EPP ConfigFileApplicationListener

  127. Карлсон строит environment

  128. Карлсон дает листенеру environment и себя

  129. ConfigFileApplicationListener Слушает • ApplicationPreparedEvent • ApplicationEnvironmentPreparedEvent Загружает • application.yml •

    application.properties • env vars • cmd args
  130. onApplicationEnvironmentPreparedEvent SpringFactoriesLoader Сгоняй за EnvironmentPostProcessor-ами

  131. onApplicationEnvironmentPreparedEvent SpringFactoriesLoader SpringFactoriesLoader. loadFactories( EnvironmentPostProcessor.class …)

  132. EPP onApplicationEnvironmentPreparedEvent SpringFactoriesLoader EPP

  133. onApplicationEnvironmentPreparedEvent EPP EPP postProcessEnvironment ща, отсортирую и поедем...

  134. onApplicationEnvironmentPreparedEvent EPP EPP postProcessEnvironment Как то он на нас похож...

  135. onApplicationEnvironmentPreparedEvent EPP EPP postProcessEnvironment Я с вами пацаны...

  136. onApplicationEnvironmentPreparedEvent EPP EPP postProcessEnvironment

  137. ConfigFileApplicationListener Слушает • ApplicationPreparedEvent • ApplicationEnvironmentPreparedEvent Загружает • application.yml •

    application.properties • env vars • cmd args spring.factories SpringFactoriesLoader
  138. spring.factories ConfigFileApplicationListener Слушает • ApplicationPreparedEvent • ApplicationEnvironmentPreparedEvent Загружает • application.yml

    • application.properties • env vars • cmd args SpringFactoriesLoader
  139. А я слышала про другие события! ContextStartedEvent ContextStoppedEvent ContextRefreshedEvent ContextClosedEvent

  140. Это Spring Boot, Тут больше event-ов

  141. Application Events ApplicationStartingEvent ApplicationEnvironmentPreparedEvent ApplicationPreparedEvent ContextRefreshedEvent EmbeddedServletContainerInitializedEvent ApplicationReadyEvent ApplicationFailedEvent ...

  142. Application Events ApplicationStartingEvent ApplicationEnvironmentPreparedEvent ApplicationPreparedEvent ContextRefreshedEvent EmbeddedServletContainerInitializedEvent ApplicationReadyEvent ApplicationFailedEvent ContextClosedEvent

  143. Application Events ApplicationStartingEvent ApplicationEnvironmentPreparedEvent ApplicationPreparedEvent ContextRefreshedEvent EmbeddedServletContainerInitializedEvent ApplicationReadyEvent ApplicationFailedEvent ContextClosedEvent

  144. Application Events ApplicationStartingEvent ApplicationEnvironmentPreparedEvent ApplicationPreparedEvent ContextRefreshedEvent EmbeddedServletContainerInitializedEvent ApplicationReadyEvent ApplicationFailedEvent ContextClosedEvent

  145. Application Events ApplicationStartingEvent ApplicationEnvironmentPreparedEvent ApplicationPreparedEvent ContextRefreshedEvent EmbeddedServletContainerInitializedEvent ApplicationReadyEvent ApplicationFailedEvent ContextClosedEvent

  146. А это, забыли? ContextStartedEvent ContextStoppedEvent

  147. Найди их место ApplicationStartingEvent ApplicationEnvironmentPreparedEvent ApplicationPreparedEvent ContextRefreshedEvent EmbeddedServletContainerInitializedEvent ApplicationReadyEvent ApplicationFailedEvent

    ContextClosedEvent ContextStartedEvent ContextStoppedEvent 1 2 3 4 5 ?
  148. Эти ивенты никогда не работают

  149. А ты их вызывать не пробовал?

  150. А ты их вызывать не пробовал? ctx.start(); → ctx.stop(); →

    ContextStartedEvent ContextStoppedEvent
  151. Где вылетит эксепшен ctx.stop(); (1) ctx.start(); (2) ctx.close(); (3) ctx.start();

    (4)
  152. Где вылетит эксепшен ctx.stop(); (1) ctx.start(); (2) ctx.close(); (3) ctx.start();

    (4) 1. на строчке (1) 2. на строчке (2) 3. на строчке (3) 4. на строчке (4)
  153. Где вылетит эксепшен ctx.stop(); (1) ctx.start(); (2) ctx.close(); (3) ctx.start();

    (4) 1. на строчке (1) 2. на строчке (2) 3. на строчке (3) 4. на строчке (4) 5. не вылетит вообще
  154. Где вылетит эксепшен ctx.stop(); (1) ctx.start(); (2) ctx.close(); (3) ctx.start();

    (4) 1. на строчке (4)
  155. Stop before Start

  156. Где вылетит эксепшен ctx.stop(); (1) ctx.start(); (2) ctx.close(); (3) ctx.start();

    (4) 1. на строчке (4)
  157. EnvironmentPostProcessor`s Application ContextInitializer`s Application ReadyEvent Тут начинается Spring Ripper Application

    StartingEvent Application EnvironmentPreparedEvent Application PreparedEvent Context RefreshedEvent EmbeddedServlet Container InitializedEvent
  158. Как запускать 1. tomcat war 2. idea 3. java -jar/war

  159. Кто пакует Jar со всеми зависимостями <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId>

    <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build>
  160. Jar как Jar, но если зайти внутрь...

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

    |- classes |- org |- springframework |- boot
  162. Анатомия SpringBoot Jar 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/ ...
  163. 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/ ...
  164. Анатомия SpringBoot Jar 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/ ... JarLauncher
  165. А кто прописывает манифест этому джару?

  166. <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <mainClass>conference...OurMainClass</mainClass> </plugin> </plugins> </build> MANIFEST.MF

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

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

    слишком сложно для нас
  169. Хочу executable jar: Maven <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration>

    <executable>true</executable> </configuration> </plugin> </plugins> </build> springBoot { executable = true } Gradle
  170. Demo. Executable jar

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

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

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

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

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

    archive Начало файла Начало zip архива
  176. Немного выводов 1. Spring Boot вышел за пределы Spring Context

    2. Starter от команды Spring отличаются от public convention ◦ не всегда в лучшую сторону 3. в Spring Boot это целый мир, в котором нет магии
  177. None
  178. @tolkv @lavcraft @jekaborisov @jeka1978

  179. Вопросы?