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
( μ¬κΈ°μ 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>>
μ κ°μ ννλ‘ μ¬μ© !
λ°μ΄ν° μμΈμ€ κ³μΈ΅μ 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 μ€ν¬λ¦½νΈ μ€μ μΆκ° ν΄μΌν¨
π‘ 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λ€κ³Ό κ·Έλ€μ μ¬μ©λ² ,,
λμ€μ μ°¨μ°¨ μ΅νκ°μΌκ² λ€.