본문 바로가기
IT/Spring

Spring WebFlux

by 최고영회 2019. 7. 19.
728x90
반응형
SMALL

Spring5에 도입된 WebFlux


Spring MVC 는 Java EE의 Servlet Spec에 기반하여 만들어 졌고 본질적으로 Blocking + 동기방식입니다.

Spring Framework 3.x부터 비동기 방식을 지원하고 있지만 

Servlet은 Response를 기다리는 동안 Pool의 Thread들을 지연시킬 수 있기 때문에 전체 stack을 Reactive하게 할 수는 없죠.

 

Reactive Programming이란?

비동기 데이터 Stream으로 Non-Blocking 어플리케이션을 구현하는 프로그래밍을 말합니다.

Stream으로 프로그래밍 한다는 것은 함수형 처리가 가능해 진다는 것을 이건 다시말해 filter 하거나 map 할 수도 

있고 여러 형태로 편하게 사용가능해 진다는 말이 됩니다. 



WebFlux는 웹 요청을 완전히 Reactive하게 처리하는 것을 가능하게 해 줍니다.


WebFlux는 기존의 Spring MVC을 대체하는 개념은 아니며 

웹어플리케이션의 용도에 맞게 MVC와 WebFlux를 함께 사용할 수 있습니다.

토비의 스프링 저자인 토비님께서는 MVC와 WebFlux를 하나의 프로젝트에 같이 사용하는 것이 좋지 않다고 말했다네요.

WebFlux는 아래와 같은 용도로 사용하는 것을 추천 한다고 합니다. (by 토비)

  • 비동기 - 논블록킹 리액티브 개발에 사용
  • 효율적으로 동작하는 고성능 웹어플리케이션 개발
  • 서비스간 호출이 많은 마이크로서비스 아키텍처에 적합



Spring5에 WebFlux가 도입되면서 동시에 Netty Embedded Server가 기본 스펙으로 추가 되었습니다.

Netty는 비동기 이벤트 기반의 고성능 네트워크 프레임워크 입니다. 

  • Tomcat: 1 request --> 1 Thread
  • Node.js: All request --> 1 Thread
  • Netty: Many request --> 1 Thread



MVC와 WebFlux의 동작흐름

  • Spring MVC 의 처리 순서에 대해서 설명해 보세요. 두개의 동작 흐름은 거의 같습니다.
  • MVC : request - Dispatcher Servlet - Handler Mapper - Controller - B/L - Controller - ViewResolver ...
  • WebFlux : request - HttpHandler - WebHandler - Handler Mapper / Handler Adapter - Controller - B/L - 이하 같음



WebFlux는 2가지 모델을 지원 합니다.

  • 기존의 @ 어노테이션 방식 : Spring MVC 기반과 동일하며 Spring MVC에서 제공하는 Annotation을 그대로 이용 가능합니다.
  • 새로운 함수형 모델 방식 : Java8 람다 식 routing과 handling 방식입니다. 가벼운 라우팅기능과 request 처리 라이브러리라고 생각하면 됩니다.
    Callback 형태로써 요청이 있을때만 호출된다는 점이 Annotation Controller 와의 차이점 입니다.



기존의 어노테이션 방식과 함수형 모델 방식의 예제 코드를 살펴 보면..

먼저 어노테이션 방식 (기존의 MVC와 거의 동일)

@RestController 
@RequiredArgsConstructor
public class TestController { 
  private final Service service; 
  
  @GetMapping("/user/{name}") 
  public Mono<User> hello(@PathVariable("name") String name){ 
    return Mono.just(Service.findByName(name)); 
  } 
}

함수형 모델 방식

@Configuration 
@EnableWebFlux 
public class TestFuncConfig { 
  @Bean 
  public RouterFunction<ServerResponse> routes(TestHandler handler) { 
    return RouterFunctions.route(GET("/userfunc"), handler::findByName); 
  } 
} 

@Component 
@RequiredArgsConstructor 
public class TestHandler { 
  private final Service service; 
  
  public Mono<ServerResponse> findByName(ServerRequest req){ 
    Mono<User> user = Mono.just(service.findByName(req.getQueryParam("name")));
    return ServerResponse.ok().body(user, User.class); 
  }
}

 

일단 오늘은 여기까지..

728x90
반응형
LIST