본문 바로가기

Web/웹 상식

Spring Webflux에 대하여

Spring webflux에 대해 찾아보고 정리한 글입니다. 일부만 정리되어 있어요, 참고 부탁드려요 ㅎㅎ

Spring webflux

Spring MVC vs Spring webflux?

spring MVC는 Servlet spec에 기반하여 만들어져 있고 Servlet API과 Servlet container를 위해 구성되어 있습니다.
여러가지 특징 중 Tomcat과 같은 WAS에 의존적인 구조이고 Spring 3.1 스펙에서는 Non-Blocking I/O를 지원하지만 본질적으로 Blocking 이고 동기방식입니다. 따라서 전체 stack을 reactive하게 만들 순 없었습니다.

 

이러한 요구사항을 만족시키기 위하여 Spirng 5부터 대안적으로 도입한 모듈이 WebFlux입니다. 웹 요청을 reactive하게 다루는 데에 초점이 맞추어져 있습니다.

 

완벽한 Non-Blocking을 지원하고 Project Reactor를 통해서 Reactive Programming을 지원합니다.
또한 MVC와는 다르게 Servlet과 관계없이 만들어져 WAS가 필요없게 되었습니다.

 

<Spring MVC와 WebFlux 구조>

 

<Spring MVC와 WebFlux 벤다이어그램>

위 그림에서 볼수있듯이 WebFlux는 MVC와 일부 호환이 됩니다.
MVC는 Servlet Container와 Servlet을 기반으로 웹 추상화 계층을 제공하는데 반해, WebFlux는 Servlet Container 뿐만 아니라,
Netty, Undertow와 같은 네트워크 애플리케이션 프레임워크도 지원합니다.
그래서 WebFlux 모듈이 포함하는 여러 기능을 이용해 2가지 프로그램 모델로 구성이 가능합니다.

 

  • Annotated Controller
    Spring MVC에서 사용하던 방식입니다. MVC에서 사용하던 어노테이션들을 WebFlux에서도 그대로 사용가능합니다.
  • Functional Endpoints
    Java 8 lambda style routing과 handling 방식입니다. callback 형태로써 요청이 있을 때만 호출된다는 점이 Annotated Controller 방식과의 차이점입니다.

<MVC 처리 흐름>

 

<WebFlux 처리 흐름>

 

위의 구조와 처리 흐름을 보면 MVC와 WebFlux는 다른 목적을 위해 만들어졌고 그에 따른 차이점을 가지지만 많은 공통점 또한 가지고 있습니다.


예시를 통해 간단하게 살펴보겠습니다.

 

@RestController
public class OssController {

	@GetMapping("/oss/{name}")
	Mono getOssName(@PathVariable String name) {
    	return Mono.just("kim");
	}
	@GetMapping("/oss")
	Flux getOssList() {
	    return Flux.just("kim", "Lee", "Park");
	}
}

 

위의 코드에서 MVC와 눈에 띄게 다른점은 반환형입니다.
WebFlux에서는 Reactive한 특징때문에 Plain Object를 사용할 수 없고 반드시 Mono, Flux와 같은 Publisher Object로 감싸서 반환해야합니다.


또 다른점은 MVC에서 어떠한 Controller가 동작해야하는지 선택하고 수행하게 하는 Handler Mapping과 Handler Adapter가 WebFlux에도 동일하게 존재하지만 동작 방식이 달라 다른 인터페이스를 사용합니다.

 

 

Mono, Flux

Mono와 Flux는 Reactive Streams 인터페이스 중에 데이터(시퀀스)를 제공하는 Publisher의 구현체입니다.
Flux 클래스를 까보면 밑의 코드처럼 되어있습니다.

 

public abstract class Flux<T> implements Publisher<T> {
    ...
}

 

Mono와 Flux의 차이점은 데이터를 전송하는 갯수의 차이가 있습니다.

  • Mono : 0 - 1 개의 데이터를 전달
  • Flux : 0 - N 개의 데이터를 전달

Mono

Flux

  • Reactive Stream 참고

아주 간단하게 예시 코드를 작성해 보았습니다.
기능은 User 모델을 조회해서 JSON으로 반환해주는 기능입니다.
Service부분은 기존의 annotation 기반 코드와 특별히 다를것이 없어
controller 부분만 작성했습니다.

 

기존의 annotation 기반이 아닌 Webflux에서 사용가능한 Funtional programming 기반 코드로 작성했습니다.

따라서 controller가 아닌 router 부분과 handler 부분으로 작동합니다.

예시 코드

Router 부분

@Configuration
@EnableWebFlux
public class UserFunctionalConfiguration {
    @Bean
    public RouterFunction<ServerResponse> routes(UserFunctionalHandler userFunctionalHandler) {
        return RouterFunctions
            .route(GET("/user/{name}").and(accept(MediaType.APPLICATION_JSON)), userFunctionalHandler::findByName)
            .andRoute(GET("/user").and(accept(MediaType.APPLICATION_JSON)), userFunctionalHandler::findAll);
    }
}

 

Handler 부분

@Component
public class UserFunctionalHandler {
    private final UserBO userBO;

    @Autowired
    UserFunctionalHandler(UserBO userBO) {
        this.userBO = userBO;
    }

    public Mono<ServerResponse> findByName(ServerRequest request) {
        return ServerResponse.ok()
            .contentType(MediaType.APPLICATION_JSON)
            .body(Mono.just(userBO.findByName(request.pathVariable("name"))), User.class);
    }

    public Mono<ServerResponse> findAll(ServerRequest request) {
        //userBO.findAll -> List<User> 반환
        return ServerResponse.ok()
            .contentType(MediaType.APPLICATION_JSON)
            .body(Flux.fromIterable(userBO.findAll()), User.class);
    }
}


아직 부족한 부분이 많아요 ㅎㅎ

틀린 부분이나 수정할만한 의견 환영합니다~ : )

 

 

 

 

 

반응형