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

これどうやって動いてるんだ? Spring Framework/Bootのソースを読む

800912a73ce4e879003b6c89cf80cfeb?s=47 yagi
February 10, 2022
730

これどうやって動いてるんだ? Spring Framework/Bootのソースを読む

800912a73ce4e879003b6c89cf80cfeb?s=128

yagi

February 10, 2022
Tweet

Transcript

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

  2. Toshihiro Yagi @sys1yagi Working at Software Engineer Spring Boot/Kotlin, Rails/Ruby,

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

  4. © Ubie, Inc. ҩྍػؔ޲͚ 4 Our Services AI ࣬ױ༧ଌ Τϯδϯ

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

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

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

  8. • Spring Framework, Spring Bootͷ֓ཁ • Spring Framework, Spring Bootͷιʔεͷ͋Γ͔ɺಡΈਐΊํ

    • REST API͕ಈ͘·ͰΛཧղ͢Δ ࠓ೔࿩͢͜ͱ 8
  9. 9 Spring Framework, Spring Bootͷ֓ཁ

  10. • 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
  11. • 2014೥ʹ1.0͕ొ৔ • ελϯυΞϩϯͷSpringΞϓϦέʔγϣϯΛ࡞੒Ͱ͖Δ • ֤छߏ੒Λߦ͏ελʔλʔΛఏڙʢWebɺόονɺϝʔϧɺϩάɺDBͳͲʣ • AutoConfigurationʹΑΔαʔυύʔςΟ΋ؚΊͨࣗಈతͳઃఆ • Spring

    Initializer͸ݱࡏ͸Spring BootΛલఏʹ͍ͯ͠Δ • https://start.spring.io/ Spring Boot 11 https://spring.io/projects/spring-boot
  12. 12 Spring Framework, Spring Bootͷ ιʔεͷ͋Γ͔ɺಡΈਐΊํ

  13. • 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
  14. IntelliJͰී௨ʹ։͚·͢ 14

  15. 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
  16. 16 Spring BootΞϓϦέʔγϣϯͷdependenciesΛ௥͏ • ϓϩδΣΫτͷπϦʔԼ෦ͷʮ֎෦ϥΠϒϥϦʯ ͔Β֤dependenciesͷৄࡉΛݟΒΕΔɻେମ sources.jar΋෇͍͍ͯΔͷͰ࣮૷Λ௥͍͔͚ΒΕ Δɻ • શମΛோΊΔͱ͖͸Spring

    Framework, BootΛ௚ ઀։͘ͷ͕ศར • ಛఆͷॲཧΛ௥͍͔͚Δͱ͖͸ΞϓϦέʔγϣϯ ͔ΒϒϨʔΫϙΠϯτுͬͯsources.jar಺Λ௥͍ ͔͚Δͷ͕ศར
  17. 17 REST API͕ಈ͘·Ͱ

  18. • 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/
  19. 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/
  20. Spring ApplicationͷΤϯτϦϙΠϯτ 20 package com.example @SpringBootApplication class ServersideKotlinApplication fun main(args:

    Array<String>) { runApplication<ServersideKotlinApplication>(*args) }
  21. 21

  22. 22

  23. SpringBootApplicationΞϊςʔγϣϯ 23 package com.example @SpringBootApplication class ServersideKotlinApplication fun main(args: Array<String>)

    { runApplication<ServersideKotlinApplication>(*args) }
  24. @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
  25. ༨ஊ: ಉ͡ΞϊςʔγϣϯΛ͚ͭͨΒಈ͘ 25 @SpringBootConfiguration @EnableAutoConfiguration @ComponentScan( excludeFilters = [ComponentScan.Filter( type

    = FilterType.CUSTOM, classes = [TypeExcludeFilter::class] ), ComponentScan.Filter(type = FilterType.CUSTOM, classes = [AutoConfigurationExcludeFilter::class])] ) class ServersideKotlinApplication
  26. ConfigurationClassParserͰίϯϙʔωϯτΛεΩϟϯ͢Δ 26 Set<AnnotationAttributes> 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ͷதͰߦ͍ͬͯΔɻ
  27. @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
  28. 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ͰΠϯελϯεΛ࡞Δ
  29. 29 @SpringBootApplication class ServersideKotlinApplication @RestController class HelloController ConfigurationClassParser ىಈ DefaultListableBeanFactory

    εΩϟϯ ॳظԽ(Πϯελϯε࡞Δ)
  30. ίϯτϩʔϥͷؔ਺ͱύεΛͲ͔͜ͰϚοϐϯά͍ͯ͠Δ͸ͣ 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
  31. • ࣗಈతͳߏ੒Λఏڙ͢ΔͷͰجຊతʹ ΞϓϦέʔγϣϯىಈ࣌ʹॲཧ͕૸Δ • ؔ܎ͦ͠͏ͳAuto ConfigurationΛؤ ுͬͯ୳ͯ͠ϒϨʔΫϙΠϯτΛுΔ ͜ͱʹͳΔ ىಈ࣌͸Bootɺ࣮ߦ࣌͸Spring͔ϥΠϒϥϦ 31

    • ΞϓϦέʔγϣϯىಈޙ͸جຊతʹ Spring͔ϥΠϒϥϦͷಈ࡞ • ϒϨʔΫϙΠϯτΛுΕ͹େମ௥͍͔ ͚ΒΕΔ • AOP͸ಈతͳͷͰͪΐͬͱ΍΍͍͜͠ 4QSJOH#PPU
  32. 32 WebܥͷػೳͳͷͰWebϞδϡʔϧʹͳΜ͔͋Γͦ͏ • spring-boot-autoconfigureͷதʹɺ ʮWebMvcAutoConfigurationʯͱ͍͏Ϋϥε͕͋Δ • spring-boot-starter-web͕ඞཁͳϞδϡʔϧΛࣗಈ Ͱ௥Ճ͍ͯ͠Δ • spring-web

    • spring-webmvc • spring-boot-autoconfigure
  33. 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ͱ͍͏໊લͰ೗Կʹ΋ո͍͠
  34. 34 ϒϨʔΫϙΠϯτΛு࣮ͬͯߦͯ͠ௐ΂Δ

  35. 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ͷॳظԽ͕͢΂ͯऴΘͬͨ͋ͱʹݺͼग़͞ΕΔؔ਺
  36. AbstractHandlerMethodMapping<T> (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();

    } ΊͬͪΌͦΕͬΆ͍
  37. AbstractHandlerMethodMapping<T> (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<Method, T> methods = MethodIntrospector.selectMethods(userType, (MethodIntrospector.MetadataLookup<T>) 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
  38. MethodIntrospector.selectMethods 38 https://github.com/spring-projects/spring-framework/blob/main/spring-core/src/main/java/org/springframework/core/MethodIntrospector.java#L84

  39. AutoConfiguration͕ىಈ࣌ʹϚοϐϯά͢ΔઃఆΛฦ͍ͯ͠Δ 39 @RestController class HelloController { @GetMapping("/") fun index(): String

    { return "Greetings from Spring Boot!" } } HelloController$index -> GET [/]
  40. ͋ͱ͸࣮ߦ͕࣌Ͳ͏ͳ͍ͬͯΔ͔ݟΔ 40

  41. 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Λ࢖ͬͯؔ਺ΛऔΓग़࣮ͯ͠ߦ ͢Δ • ϨεϙϯεΛॲཧ͢ΔՕॴͳͲʹ

    ΋ͨͲΓண͚Δ
  42. دΓಓ 42

  43. suspendʹͯ͠ΈΔ 43 @RestController class HelloController { @GetMapping("/") suspend fun index():

    String { return "Greetings from Spring Boot! $coroutineContext" } }
  44. ΊͬͪΌΤϥʔͰίέΔ͕… 44

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

  46. ͍͚Δ 46

  47. • Spring Framework/Bootͷιʔε͸Githubʹ͋ΔɻIntelliJͰ։͚Δ • Spring Framework͕ίϯϙʔωϯτεΩϟϯͰΠϯελϯεΛ࡞ͬͨΓॳظԽͨ͠ΓDI͍ͯͯ͠ɺىಈϓϩηεΛ ಡΜͰ͍͘ͱΘ͔Δ • Spring Boot͕ϞδϡʔϧͷॳظઃఆܥΛAuto

    ConfigurationʹΑͬͯߦ͍ͬͯΔɻউखʹಈ͖ग़͢ܥ͸େମAuto ConfigurationΛ୳ͤ͹ݟ͔ͭΔ • @RestController͕෇͍ͨΫϥε͸ίϯϙʔωϯτεΩϟϯͰΠϯελϯε͕࡞ΒΕɺ RequestMappingHandlerMappingʹΑͬͯؔ਺ͱύεͱϝιου͕ඥ෇͚ΒΕΔ • ϦΫΤετΛड͚ͯؔ਺Λݺͼग़͍ͯ͠Δͷ͸InvocableHandlerMethodɻϒϨʔΫϙΠϯτுΕ͹ಈ͔͠ͳ͕Β ௥͑Δ ·ͱΊ 47
  48. 48 Thank You