🌈 [Section4] 9. [Spring WebFlux] Spring WebFlux

ν˜„μ£ΌΒ·2022λ…„ 12μ›” 1일
0

bootcamp

λͺ©λ‘ 보기
63/71
post-thumbnail

πŸ“• 였늘 배운 λ‚΄μš©!

  • Spring WebFlux
  • Spring WebFlux μ• ν”Œλ¦¬μΌ€μ΄μ…˜ vs Spring MVC μ• ν”Œλ¦¬μΌ€μ΄μ…˜
  • Spring MVC μ• ν”Œλ¦¬μΌ€μ΄μ…˜ ➜ Spring WebFlux μ• ν”Œλ¦¬μΌ€μ΄μ…˜ λ³€ν™˜

✏️ Spring WebFlux

The reactive-stack web framework, Spring WebFlux, was added later in version 5.0.
( from Spring 곡식 μ‚¬μ΄νŠΈ )

  • Spring 5λΆ€ν„° μ§€μ›ν•˜λŠ” λ¦¬μ•‘ν‹°λΈŒ μ›Ή μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ„ μœ„ν•œ μ›Ή ν”„λ ˆμž„μ›Œν¬

  • 이λ₯Ό μ‚¬μš©ν•΄μ„œ λ¦¬μ•‘ν‹°λΈŒν•œ μ›Ή μ• ν”Œλ¦¬μΌ€μ΄μ…˜ κ΅¬ν˜„ κ°€λŠ₯

  • λ¦¬μ•‘ν‹°λΈŒ 슀트림즈(Reactive Streams)의 사양인 μΈν„°νŽ˜μ΄μŠ€λ₯Ό 기반으둜 λ™μž‘
    ➜ λ¦¬μ•‘ν‹°λΈŒ 슀트림즈λ₯Ό κ΅¬ν˜„ν•œ κ΅¬ν˜„μ²΄λΌλ©΄ λŒ€λΆ€λΆ„ Reactor λŒ€μ‹  μ‚¬μš© κ°€λŠ₯
    ( Reactor μ΄μ™Έμ˜ λ¦¬μ•‘ν‹°λΈŒ λΌμ΄λΈŒλŸ¬λ¦¬λŠ” ReactiveAdapter와 ReactiveAdapterRegistryλ₯Ό 톡해 μ‚¬μš© κ°€λŠ₯ )

ReactiveAdapter μ°Έκ³ 
ReactiveAdapterRegistry μ°Έκ³ 

βœ”οΈ WebFlux
μ‰½κ²Œ 말해 μ›Ή μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ—μ„œ μ‚¬μš©ν•  수 μžˆλŠ” Flux + Web


✏️ Spring WebFlux μ• ν”Œλ¦¬μΌ€μ΄μ…˜ vs Spring MVC μ• ν”Œλ¦¬μΌ€μ΄μ…˜

βœ” 기술 μŠ€νƒ 비ꡐ

( μ—¬κΈ°μ„œ Reactive Stack이 Spring WebFlux / Servlet Stack이 Spring MVC에 ν•΄λ‹Ή )

기술 μŠ€νƒ 비ꡐ μ°Έκ³ 

β‘ 
➜ Spring WebFlux πŸ‘‰ Non-Blocking 톡신 방식

➜ Spring MVC πŸ‘‰ Blocking 톡신 방식

β‘‘
➜ Spring WebFlux πŸ‘‰ Reactive Adapterλ₯Ό μ‚¬μš©ν•˜μ—¬ Reactor 뿐만 μ•„λ‹ˆλΌ RxJava λ“± λ‹€λ₯Έ λ¦¬μ•‘ν‹°λΈŒ 라이브러리λ₯Ό μ‚¬μš©ν•  수 μžˆλŠ” μœ μ—°ν•¨ 제곡

➜ Spring MVC πŸ‘‰ Servlet API μŠ€νŽ™μ— 의쑴적

β‘’
( Spring WebFlux / Spring MVC λͺ¨λ‘ λ³΄μ•ˆμ„ μœ„ν•΄ Spring Security μ‚¬μš© )

➜ Spring WebFlux πŸ‘‰ WebFilterλ₯Ό μ‚¬μš©ν•΄ λ¦¬μ•‘ν‹°λΈŒ νŠΉμ„±μ— 맞게 λ³΄μ•ˆ 적용

➜ Spring MVC πŸ‘‰ μ„œλΈ”λ¦Ώ ν•„ν„° λ°©μ‹μœΌλ‘œ λ³΄μ•ˆ 적용

β‘£
➜ Reactive Stack πŸ‘‰ μ›Ή 계측(ν”„λ¦¬μ  ν…Œμ΄μ…˜ 계측, API 계측)μ—μ„œλŠ” Spring WebFlux μ‚¬μš©
➜ Servlet Stack πŸ‘‰ Spring MVC μ‚¬μš©

β‘€
➜ Spring WebFlux πŸ‘‰ μ™„μ „ν•œ Non-Blocking 톡신을 μœ„ν•΄ λ¦¬μ•‘ν‹°λΈŒ μŠ€νƒμ„ 데이터 μ•‘μ„ΈμŠ€ κ³„μΈ΅κΉŒμ§€ ν™•μž₯
➜ Spring MVC πŸ‘‰ Repository μ‚¬μš©

βœ”οΈ R2DBC (Reactive Relation Database Connectivity)
➜ κ΄€κ³„ν˜• λ°μ΄ν„°λ² μ΄μŠ€μ— Non-Blocking 톡신을 μ μš©ν•˜κΈ° μœ„ν•œ ν‘œμ€€ 사양(Specification)
➜ MySQL, Oracle λ“±μ˜ λ°μ΄ν„°λ² μ΄μŠ€ λ²€λ”μ—μ„œλŠ” R2DBC 사양에 λ§žλŠ” λ“œλΌμ΄λ²„λ₯Ό κ΅¬ν˜„ν•˜μ—¬ 곡급

βœ” λ²€ λ‹€μ΄μ–΄κ·Έλž¨μ„ ν†΅ν•œ 비ꡐ


λ²€ λ‹€μ΄μ–΄κ·Έλž¨μ„ ν†΅ν•œ 비ꡐ μ°Έκ³ 

( ⬆️ μœ„ λ²€λ‹€μ΄μ–΄κ·Έλž¨μ„ 톡해 각각의 차이점과 곡톡점을 μ•Œ 수 있음 )

  • 곡톡점

    • @Controleller(or @RestController) 같은 μ• λ„ˆν…Œμ΄μ…˜μ˜ μ‚¬μš©

    • RestTemplate을 λŒ€μ²΄ν•  수 μžˆλŠ” WebClient의 μ‚¬μš©
      WebClient μ°Έκ³  1
      WebClient μ°Έκ³  2

    • Tomcat, Jetty λ“±μ˜ μ„œλΈ”λ¦Ώ μ»¨ν…Œμ΄λ„ˆλ„ 두 방식 λͺ¨λ‘ 지원

❗ λ™μž‘ 방식은 μ „ν˜€ λ‹€λ₯΄μ§€λ§Œ ν”„λ ˆμž„μ›Œν¬λ₯Ό μ‚¬μš©ν•˜λŠ” μ‚¬μš©μž μž…μž₯을 κ³ λ €ν•˜μ—¬
μ΅œμ†Œν•œμ˜ λ³€κ²½ 포인트만 μœ μ§€ν•˜λ©΄μ„œ μΌκ΄€λœ μ ‘κ·Ό λ°©μ‹μœΌλ‘œ 두 κΈ°μˆ μ„ μ‚¬μš©ν•  수 μžˆλ„λ‘ λΉ„μŠ·ν•˜κ²Œ ꡬ성함
β €
➜ Springμ—μ„œ μΆ”κ΅¬ν•˜λŠ” μΌκ΄€λœ μ„œλΉ„μŠ€ 좔상화(PSA)κ°€ κ°œλ…μ μœΌλ‘œ λ°˜μ˜λ˜μ–΄ μžˆλ‹€κ³  λ³Ό 수 있음

βœ” μƒ˜ν”Œ μ½”λ“œλ₯Ό ν†΅ν•œ 비ꡐ

( projects - be-template-webflux 내에 비ꡐ μ½”λ“œ 있음 )

❗ main 클래슀(ν΄λΌμ΄μ–ΈνŠΈ) ➜ λ‚΄λΆ€ μ„œλ²„ (8080) ➜ μ™ΈλΆ€ μ„œλ²„ (7070) 의 μˆœμ„œλ‘œ λ™μž‘

βœ” 결정적인 차이점

  • βœ”οΈ Spring MVC

    β‘  Threadκ°€ μ°¨λ‹¨λ˜λŠ” Blocking I/O 방식

    ➜ SpringMvcMainSampleApplication 클래슀의 μ‹€ν–‰ κ²°κ³Όλ₯Ό 보면,
    5개의 μš”μ²­λ§ˆλ‹€ μ—¬λŸ¬κ°œμ˜ μ“°λ ˆλ“œκ°€ 순차적으둜 λ™μž‘ν•˜μ—¬ 총 25초 κ±Έλ¦Ό

    β‘‘ Thread λͺ¨λΈ
    ➜ request λ‹Ή 맀번 thread ν•˜λ‚˜κ°€ λ§€ν•‘λ˜μ–΄ μ²˜λ¦¬ν•˜λŠ” 방식
    ( A thread per request )

    β‘’ ν•Έλ“€λŸ¬ λ©”μ„œλ“œμ˜ λ¦¬ν„΄νƒ€μž…μ„ ResponseEntity μ‚¬μš©
    Ex. ResponseEntity<CoffeeResponseDto>

  • βœ”οΈ Spring WebFlux

    β‘  Threadκ°€ μ°¨λ‹¨λ˜μ§€ μ•ŠλŠ” Non-Blocking I/O 방식

    ➜ SpringWebFluxMainSampleApplication 클래슀의 μ‹€ν–‰ κ²°κ³Όλ₯Ό 보면,
    ν•˜λ‚˜μ˜ μ“°λ ˆλ“œμ—μ„œ μ—¬λŸ¬κ°œμ˜ μš”μ²­μ„ ν•œλ²ˆμ— λ°›μ•„ 거의 λ™μ‹œμ— λ™μž‘ν•˜μ—¬ 총 6초 κ±Έλ¦Ό

    β‘‘ Thread λͺ¨λΈ
    ➜ CPU μ½”μ–΄ 개수만큼의 적은 μ“°λ ˆλ“œλ‘œ λŒ€λŸ‰μ˜ νŠΈλž˜ν”½μ„ μ²˜λ¦¬ν•˜λŠ” 이벀트 루프(Event loop) 방식

    βœ”οΈ 이벀트 루프 (Event loop)

    • λΈŒλΌμš°μ € 메인 μŠ€λ ˆλ“œ λ™μž‘ 타이밍을 κ΄€λ¦¬ν•˜λŠ” κ΄€λ¦¬μž
    • μž‘μ—… κ°„ μ „ν™˜ 속도λ₯Ό λΉ λ₯΄κ²Œ ν•˜μ—¬, ν•œ λ²ˆμ— ν•˜λ‚˜μ˜ μž‘μ—…μ”© μˆ˜ν–‰ν•˜μ§€λ§Œ 마치 λ™μ‹œμ— μˆ˜ν–‰ν•˜λŠ” κ²ƒμ²˜λŸΌ λ™μž‘μ‹œν‚΄
      [μ°Έκ³ ] https://tecoble.techcourse.co.kr/post/2021-08-28-event-loop/

    β‘’ ν•Έλ“€λŸ¬ λ©”μ„œλ“œμ˜ λ¦¬ν„΄νƒ€μž…μ„ Mono or Flux μ‚¬μš©
    Ex. Mono<CoffeeResponseDto>

    πŸ’‘ Spring WebFluxμ—μ„œλ„ ResponseEntityκ°€ μ‚¬μš©λ˜κΈ°λŠ” ν•˜μ§€λ§Œ,
    ResponseEntity<Mono<CoffeeResponseDto>> 와 같은 ν˜•νƒœλ‘œ μ‚¬μš© !


✏️ Spring MVC μ• ν”Œλ¦¬μΌ€μ΄μ…˜ ➜ Spring WebFlux μ• ν”Œλ¦¬μΌ€μ΄μ…˜ λ³€ν™˜

  • 데이터 μ—‘μ„ΈμŠ€ 계측은 Non-Blocking I/Oλ₯Ό μ§€μ›ν•˜λŠ” R2DBC μ‚¬μš©
    R2dbcEntityTemplate μ°Έκ³  1
    R2dbcEntityTemplate μ°Έκ³  2

  • μ—°κ΄€ 관계 맀핑 지원 X
    ( ν…Œμ΄λΈ” 내에 μ™Έλž˜ν‚€λ₯Ό κ·Έλƒ₯ 써주면 됨 )

  • λͺ¨λ“  둜직이 Mono or Flux Operator 체인 내에 μž‘μ„±
    ( Operator둜 μ‹œμž‘ν•΄μ„œ ~ Operator둜 λλ‚œλ‹€ )
    ➜ Spring WebFlux 기반 ν΄λž˜μŠ€λŠ” Mono or Flux둜 λž˜ν•‘ν•œ 값을 리턴

⚠️ μ£Όμ˜ν•  점

  • Spring λ¦¬μ•‘ν‹°λΈŒ μŠ€νƒμ˜ 경우, H2 μ›Ή μ½˜μ†”μ„ μ •μƒμ μœΌλ‘œ 지원 X

  • Spring Data R2DBCλŠ” Auto DDL κΈ°λŠ₯을 μ œκ³΅ν•˜μ§€ μ•ŠμŒ
    ➜ 직접 SQL 슀크립트 μ„€μ • μΆ”κ°€ 해야함


😜 μ‹€μŠ΅

  • projects - be-template-webflux
  • git - be-homework-webflux

πŸ’‘ Spring λ¦¬μ•‘ν‹°λΈŒ μŠ€νƒμ˜ 경우, H2 μ›Ή μ½˜μ†”μ„ μ •μƒμ μœΌλ‘œ 지원 X 라고 ν–ˆμ—ˆλŠ”λ°

  • build.gradle νŒŒμΌμ— μ•„λž˜μ™€ 같이 h2 μ˜μ‘΄μ„± μΆ”κ°€ν•΄μ£Όκ³ ,
    implementation 'com.h2database:h2' // μΆ”κ°€

( 쿼리문은 r2dbc 둜 λ‚˜κ° )

  • application.yml νŒŒμΌμ— μ•„λž˜μ™€ 같이 μΆ”κ°€ ν•΄μ£Όκ³ ,

    r2dbc:
        url: r2dbc:h2:mem:///test;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
        username: sa
        password:
  • μ•„λž˜μ™€ 같이 λ§Œλ“€λ©΄ 8078 포트둜 h2 console에 μ§„μž… κ°€λŠ₯ν•˜λŒ€ !!

    @Slf4j
    @Component
    //@Profile("local")
    public class H2Console {
       private Server webServer;
    β €
       @EventListener(ContextRefreshedEvent.class)
       public void start() throws java.sql.SQLException {
          log.info("starting h2 console at port 8078");
          this.webServer = org.h2.tools.Server.createWebServer("-webPort", "8078", "-tcpAllowOthers").start();
       }
    β €
       @EventListener(ContextClosedEvent.class)
       public void stop() {
          log.info("stopping h2 console at port 8078");
          this.webServer.stop();
       }

🌈 λŠλ‚€μ 

κ·Έλž˜λ„ 이틀간 κ°œλ…λ§Œ κ³΅λΆ€ν–ˆλ˜ 것 보닀 직접 μ½”λ“œλ₯Ό 치고 Spring MVCμ—μ„œ Spring WebFlux 둜 λ³€κ²½ν•˜μ—¬ μ μš©ν•˜λ‹€λ³΄λ‹ˆ 더 이해가 잘 됐던 것 κ°™λ‹€ !
κ·Έλž˜λ„ 방식은 어렡지 μ•Šμ€λ° μ € μ–΄λ €μš΄ 게 μžˆλ‹€λ©΄ λ„ˆλ¬΄ λ§Žμ€ Operatorλ“€κ³Ό κ·Έλ“€μ˜ μ‚¬μš©λ²• ,,
λ‚˜μ€‘μ— μ°¨μ°¨ μ΅ν˜€κ°€μ•Όκ² λ‹€.

0개의 λŒ“κΈ€