Slide 1

Slide 1 text

͜ΕͲ͏΍ͬͯಈ͍ͯΔΜͩʁ Spring Framework/BootͷιʔεΛಡΉ 2022/02/10 Server-Side Kotlin Meetup vol.1

Slide 2

Slide 2 text

Toshihiro Yagi @sys1yagi Working at Software Engineer Spring Boot/Kotlin, Rails/Ruby, React/TypeScript About Me 2

Slide 3

Slide 3 text

Our Services 3 ҩྍػؔ޲͚ AI໰਍γεςϜ (toB) ੜ׆ऀ޲͚ ड਍૬ஊΞϓϦ (toC)

Slide 4

Slide 4 text

© Ubie, Inc. ҩྍػؔ޲͚ 4 Our Services AI ࣬ױ༧ଌ Τϯδϯ OCR ҩྍ৘ใ ςΩετԽ ݕࠪ αδΣετ ॲํༀ ݕࡧ Χϧς ੜ੒ ॳ਍ ໰਍ ࠶਍ ໰਍ ిࢠΧϧς ࿈ܞ Ӄ಺ γεςϜ ࿈ܞ ஍Ҭҩྍ ࿈ܞ ܦӦ؅ཧ ॲํ αδΣετ ॲํ ࿈ܞ ٹٸҩྍ αϙʔτ ೖӃ αϙʔτ ঱ঢ় νΣοΧʔ ҩྍػؔ Λ୳͢ ҩྍػؔ ࿈ܞ ҩྍػؔ ࣄલ໰਍ ద੾ͳ ਍ྍՊ Ҋ಺ ঱ঢ় ܦա؍࡯ ड਍ ༧໿ ड਍ αϙʔτ ϝσΟΞ ݈߁ཤྺ Ұݩ؅ཧ ҩྍػؔ޲͚ CRM ࢢൢༀ ݕࡧ ප໊ ࣙॻ ࣬ױܒൃ ઐ໳ҩྍػؔ Ҋ಺ AI࣬ױ༧ଌΤϯδϯΛத৺ʹɺtoCɺtoB྆໘Ͱࠓޙ΋৽ͨͳϓϩμΫτΛಉ࣌ʹ࡞͍ͬͯ͘༧ఆͰ͢ ҰൠϢʔβ޲͚ https://recruit.ubie.life/engineer

Slide 5

Slide 5 text

5 Spring Boot࢖͍ͬͯΔํ Ͳͷ͘Β͍͍·͔͢ʁ

Slide 6

Slide 6 text

6 Spring Framework΋ Spring Boot΋ ͔ͳΓϚδΧϧ 🤔

Slide 7

Slide 7 text

7 ιʔεΛಡΊ͹ ͍͍ͩͨ෼͔Δ 😇

Slide 8

Slide 8 text

• Spring Framework, Spring Bootͷ֓ཁ • Spring Framework, Spring Bootͷιʔεͷ͋Γ͔ɺಡΈਐΊํ • REST API͕ಈ͘·ͰΛཧղ͢Δ ࠓ೔࿩͢͜ͱ 8

Slide 9

Slide 9 text

9 Spring Framework, Spring Bootͷ֓ཁ

Slide 10

Slide 10 text

• 2004೥ʹਖ਼ࣜϦϦʔεɻJavaΞϓϦέʔγϣϯ༻ͷϑϨʔϜϫʔΫ • Inversion of control͕த৺తͳػೳ • AOPɺσʔλΞΫηεϑϨʔϜϫʔΫɺτϥϯβΫγϣϯɺMVCɺϦϞʔτΞΫη εɺόονͳͲͷϞδϡʔϧ͕͋Δ • 2018೥9݄ Spring Framework 5.1 ͔Β Kotlin 1.1αϙʔτ • https://spring.pleiades.io/guides/tutorials/spring-boot-kotlin/ Spring Framework 10 https://en.wikipedia.org/wiki/Spring_Framework

Slide 11

Slide 11 text

• 2014೥ʹ1.0͕ొ৔ • ελϯυΞϩϯͷSpringΞϓϦέʔγϣϯΛ࡞੒Ͱ͖Δ • ֤छߏ੒Λߦ͏ελʔλʔΛఏڙʢWebɺόονɺϝʔϧɺϩάɺDBͳͲʣ • AutoConfigurationʹΑΔαʔυύʔςΟ΋ؚΊͨࣗಈతͳઃఆ • Spring Initializer͸ݱࡏ͸Spring BootΛલఏʹ͍ͯ͠Δ • https://start.spring.io/ Spring Boot 11 https://spring.io/projects/spring-boot

Slide 12

Slide 12 text

12 Spring Framework, Spring Bootͷ ιʔεͷ͋Γ͔ɺಡΈਐΊํ

Slide 13

Slide 13 text

• Spring Framework • https://github.com/spring-projects/spring-framework • git clone --depth 1 git@github.com:spring-projects/spring-framework.git • Spring Boot • https://github.com/spring-projects/spring-boot • git clone --depth 1 git@github.com:spring-projects/spring-boot.git Spring FrameworkͱBootͷιʔε͸Githubʹ͋Δ 13

Slide 14

Slide 14 text

IntelliJͰී௨ʹ։͚·͢ 14

Slide 15

Slide 15 text

15 ར༻όʔδϣϯʹ߹ΘͤͯϒϥϯνΛ੾Γସ͑Δ αΠυόʔͷGradleͰґଘؔ܎ΛݟΔͱௐ΂ΒΕΔ • Spring Boot 2.6.3 • git checkout -b 2.6.x origin/2.6.x • Spring Framework 5.3.15 • git checkout -b 5.3.x origin/5.3.x

Slide 16

Slide 16 text

16 Spring BootΞϓϦέʔγϣϯͷdependenciesΛ௥͏ • ϓϩδΣΫτͷπϦʔԼ෦ͷʮ֎෦ϥΠϒϥϦʯ ͔Β֤dependenciesͷৄࡉΛݟΒΕΔɻେମ sources.jar΋෇͍͍ͯΔͷͰ࣮૷Λ௥͍͔͚ΒΕ Δɻ • શମΛோΊΔͱ͖͸Spring Framework, BootΛ௚ ઀։͘ͷ͕ศར • ಛఆͷॲཧΛ௥͍͔͚Δͱ͖͸ΞϓϦέʔγϣϯ ͔ΒϒϨʔΫϙΠϯτுͬͯsources.jar಺Λ௥͍ ͔͚Δͷ͕ศར

Slide 17

Slide 17 text

17 REST API͕ಈ͘·Ͱ

Slide 18

Slide 18 text

• Spring InitializerͰSpring Web͚ͩબ୒ Dependencies 18 implementation("org.springframework.boot:spring-boot-starter-web") implementation("com.fasterxml.jackson.module:jackson-module-kotlin") implementation("org.jetbrains.kotlin:kotlin-reflect") implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") https://start.spring.io/

Slide 19

Slide 19 text

APIΛ࣮૷͢Δ 19 package com.example.controller @RestController class HelloController { @GetMapping("/") fun index(): String { return "Greetings from Spring Boot!" } } https://spring.io/guides/gs/spring-boot/

Slide 20

Slide 20 text

Spring ApplicationͷΤϯτϦϙΠϯτ 20 package com.example @SpringBootApplication class ServersideKotlinApplication fun main(args: Array) { runApplication(*args) }

Slide 21

Slide 21 text

21

Slide 22

Slide 22 text

22

Slide 23

Slide 23 text

SpringBootApplicationΞϊςʔγϣϯ 23 package com.example @SpringBootApplication class ServersideKotlinApplication fun main(args: Array) { runApplication(*args) }

Slide 24

Slide 24 text

@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 { SpringBootApplicationΞϊςʔγϣϯ 24 https://github.com/spring-projects/spring-boot/blob/main/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/SpringBootApplication.java ෳ਺ͷΞϊςʔγϣϯΛ߹੒͍ͯ͠Δ AutoConfigurationΛ༗ޮʹ͢Δ DIͷͨΊͷίϯϙʔωϯτͳͲΛεΩϟϯ͢Δઃఆ 4QSJOH#PPU

Slide 25

Slide 25 text

༨ஊ: ಉ͡ΞϊςʔγϣϯΛ͚ͭͨΒಈ͘ 25 @SpringBootConfiguration @EnableAutoConfiguration @ComponentScan( excludeFilters = [ComponentScan.Filter( type = FilterType.CUSTOM, classes = [TypeExcludeFilter::class] ), ComponentScan.Filter(type = FilterType.CUSTOM, classes = [AutoConfigurationExcludeFilter::class])] ) class ServersideKotlinApplication

Slide 26

Slide 26 text

ConfigurationClassParserͰίϯϙʔωϯτΛεΩϟϯ͢Δ 26 Set componentScans = AnnotationConfigUtils.attributesForRepeatable( sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class ); if (!componentScans.isEmpty()… https://github.com/spring-projects/spring-framework/blob/main/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassParser.java#L289 ͜ͷΞϊςʔγϣϯͷ෇͍ͨΫϥεͷύοέʔδ഑ԼΛ૞ࠪ͠ɺΠϯελϯεͷ ੜ੒΍ॳظԽॲཧΛߦ͏ɻSpringApplicationͷதͰߦ͍ͬͯΔɻ

Slide 27

Slide 27 text

@RestController΋ComponentΞϊςʔγϣϯΛ߹੒͍ͯ͠Δ 27 @RestController class HelloController { @GetMapping("/") fun index(): String { return "Greetings from Spring Boot!" } } ίϯϙʔωϯτεΩϟϯͷର৅ʹͳΔ https://github.com/spring-projects/spring-framework/blob/main/spring-web/src/main/java/org/springframework/web/bind/annotation/RestController.java

Slide 28

Slide 28 text

DefaultListableBeanFactoryͰΠϯελϯεΛ࡞Δ 28 for (String beanName : beanNames) { RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName); if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) { if (isFactoryBean(beanName)) { // লུ } else { getBean(beanName); } } } https://github.com/spring-projects/spring-framework/blob/main/spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java#L908 ίϯϙʔωϯτεΩϟϯͰूΊͨ৘ใΛ࢖ͬͯDefaultListableBeanFactoryͰΠϯελϯεΛ࡞Δ

Slide 29

Slide 29 text

29 @SpringBootApplication class ServersideKotlinApplication @RestController class HelloController ConfigurationClassParser ىಈ DefaultListableBeanFactory εΩϟϯ ॳظԽ(Πϯελϯε࡞Δ)

Slide 30

Slide 30 text

ίϯτϩʔϥͷؔ਺ͱύεΛͲ͔͜ͰϚοϐϯά͍ͯ͠Δ͸ͣ 30 @RestController class HelloController { @GetMapping("/") fun index(): String { return "Greetings from Spring Boot!" } } HelloController$index -> GET [/] https://github.com/spring-projects/spring-framework/blob/main/spring-web/src/main/java/org/springframework/web/bind/annotation/GetMapping.java#L46

Slide 31

Slide 31 text

• ࣗಈతͳߏ੒Λఏڙ͢ΔͷͰجຊతʹ ΞϓϦέʔγϣϯىಈ࣌ʹॲཧ͕૸Δ • ؔ܎ͦ͠͏ͳAuto ConfigurationΛؤ ுͬͯ୳ͯ͠ϒϨʔΫϙΠϯτΛுΔ ͜ͱʹͳΔ ىಈ࣌͸Bootɺ࣮ߦ࣌͸Spring͔ϥΠϒϥϦ 31 • ΞϓϦέʔγϣϯىಈޙ͸جຊతʹ Spring͔ϥΠϒϥϦͷಈ࡞ • ϒϨʔΫϙΠϯτΛுΕ͹େମ௥͍͔ ͚ΒΕΔ • AOP͸ಈతͳͷͰͪΐͬͱ΍΍͍͜͠ 4QSJOH#PPU

Slide 32

Slide 32 text

32 WebܥͷػೳͳͷͰWebϞδϡʔϧʹͳΜ͔͋Γͦ͏ • spring-boot-autoconfigureͷதʹɺ ʮWebMvcAutoConfigurationʯͱ͍͏Ϋϥε͕͋Δ • spring-boot-starter-web͕ඞཁͳϞδϡʔϧΛࣗಈ Ͱ௥Ճ͍ͯ͠Δ • spring-web • spring-webmvc • spring-boot-autoconfigure

Slide 33

Slide 33 text

WebMvcAutoConfigurationͰո͍͠BeanΛ୳͢ 33 4QSJOH#PPU @Bean @Primary @Override public RequestMappingHandlerMapping requestMappingHandlerMapping( @Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager, @Qualifier("mvcConversionService") FormattingConversionService conversionService, @Qualifier("mvcResourceUrlProvider") ResourceUrlProvider resourceUrlProvider) { // Must be @Primary for MvcUriComponentsBuilder to work return super.requestMappingHandlerMapping(contentNegotiationManager, conversionService, resourceUrlProvider); } https://github.com/spring-projects/spring-boot/blob/main/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfiguration.java#L439 • GetMapping͸RequestMappingΛ߹੒͍ͯ͠ΔΞϊςʔγϣϯ • RequestMappingHandlerMappingͱ͍͏໊લͰ೗Կʹ΋ո͍͠

Slide 34

Slide 34 text

34 ϒϨʔΫϙΠϯτΛு࣮ͬͯߦͯ͠ௐ΂Δ

Slide 35

Slide 35 text

RequestMappingHandlerMappingͰϦΫΤετύεͱؔ਺Λඥ͚͍ͭͯΔ 35 https://github.com/spring-projects/spring-framework/blob/main/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerMapping.java#L205 public void afterPropertiesSet() { this.config = new RequestMappingInfo.BuilderConfiguration(); this.config.setTrailingSlashMatch(useTrailingSlashMatch()); this.config.setContentNegotiationManager(getContentNegotiationManager()); // ུ super.afterPropertiesSet(); } BeanͷॳظԽ͕͢΂ͯऴΘͬͨ͋ͱʹݺͼग़͞ΕΔؔ਺

Slide 36

Slide 36 text

AbstractHandlerMethodMapping (RequestMappingHandlerMappͷεʔύʔΫϥε) 36 https://github.com/spring-projects/spring-framework/blob/main/spring-webmvc/src/main/java/org/springframework/web/servlet/handler/AbstractHandlerMethodMapping.java#L212 @Override public void afterPropertiesSet() { initHandlerMethods(); } ΊͬͪΌͦΕͬΆ͍

Slide 37

Slide 37 text

AbstractHandlerMethodMapping (RequestMappingHandlerMappͷεʔύʔΫϥε) 37 protected void detectHandlerMethods(Object handler) { Class> handlerType = (handler instanceof String ? obtainApplicationContext().getType((String) handler) : handler.getClass()); if (handlerType != null) { Class> userType = ClassUtils.getUserClass(handlerType); Map methods = MethodIntrospector.selectMethods(userType, (MethodIntrospector.MetadataLookup) method -> { try { return getMappingForMethod(method, userType); // ུ } https://github.com/spring-projects/spring-framework/blob/a0c97e4c36e5e07bc13bab4409ec740332a57871/spring-webmvc/src/main/java/org/springframework/web/servlet/handler/AbstractHandlerMethodMapping.java#L275

Slide 38

Slide 38 text

MethodIntrospector.selectMethods 38 https://github.com/spring-projects/spring-framework/blob/main/spring-core/src/main/java/org/springframework/core/MethodIntrospector.java#L84

Slide 39

Slide 39 text

AutoConfiguration͕ىಈ࣌ʹϚοϐϯά͢ΔઃఆΛฦ͍ͯ͠Δ 39 @RestController class HelloController { @GetMapping("/") fun index(): String { return "Greetings from Spring Boot!" } } HelloController$index -> GET [/]

Slide 40

Slide 40 text

͋ͱ͸࣮ߦ͕࣌Ͳ͏ͳ͍ͬͯΔ͔ݟΔ 40

Slide 41

Slide 41 text

InvocableHandlerMethodͰؔ਺Λ࣮ߦ͍ͯ͠Δ 41 https://github.com/spring-projects/spring-framework/blob/main/spring-web/src/main/java/org/springframework/web/method/support/InvocableHandlerMethod.java#L205 • HttpServletRequestͱ RequestMappingHandlerAdapt erΛ࢖ͬͯؔ਺ΛऔΓग़࣮ͯ͠ߦ ͢Δ • ϨεϙϯεΛॲཧ͢ΔՕॴͳͲʹ ΋ͨͲΓண͚Δ

Slide 42

Slide 42 text

دΓಓ 42

Slide 43

Slide 43 text

suspendʹͯ͠ΈΔ 43 @RestController class HelloController { @GetMapping("/") suspend fun index(): String { return "Greetings from Spring Boot! $coroutineContext" } }

Slide 44

Slide 44 text

ΊͬͪΌΤϥʔͰίέΔ͕… 44

Slide 45

Slide 45 text

ΊͬͪΌΤϥʔͰίέΔ͕… 45 implementation(“io.projectreactor.kotlin:reactor-kotlin-extensions") implementation("org.jetbrains.kotlinx:kotlinx-coroutines-reactor") ඞཁͳϥΠϒϥϦΛ௥Ճ͢Ε͹͍͚ΔͷͰ͸ʁ

Slide 46

Slide 46 text

͍͚Δ 46

Slide 47

Slide 47 text

• Spring Framework/Bootͷιʔε͸Githubʹ͋ΔɻIntelliJͰ։͚Δ • Spring Framework͕ίϯϙʔωϯτεΩϟϯͰΠϯελϯεΛ࡞ͬͨΓॳظԽͨ͠ΓDI͍ͯͯ͠ɺىಈϓϩηεΛ ಡΜͰ͍͘ͱΘ͔Δ • Spring Boot͕ϞδϡʔϧͷॳظઃఆܥΛAuto ConfigurationʹΑͬͯߦ͍ͬͯΔɻউखʹಈ͖ग़͢ܥ͸େମAuto ConfigurationΛ୳ͤ͹ݟ͔ͭΔ • @RestController͕෇͍ͨΫϥε͸ίϯϙʔωϯτεΩϟϯͰΠϯελϯε͕࡞ΒΕɺ RequestMappingHandlerMappingʹΑͬͯؔ਺ͱύεͱϝιου͕ඥ෇͚ΒΕΔ • ϦΫΤετΛड͚ͯؔ਺Λݺͼग़͍ͯ͠Δͷ͸InvocableHandlerMethodɻϒϨʔΫϙΠϯτுΕ͹ಈ͔͠ͳ͕Β ௥͑Δ ·ͱΊ 47

Slide 48

Slide 48 text

48 Thank You