[75일차]WebFlux

유태형·2022년 8월 14일
0

코드스테이츠

목록 보기
74/77

오늘의 목표

  1. WebFlux 개념
  2. SpringMVC, WebFlux 비교



내용

WebFlux 개념

Spring5 버전에서 새롭게 추가된 기술 스틱이 바로 리액티브(Reactive)스택이자 웹 프레임워크입니다.

FluxReactorMono와 함께 사용되는 N개 이상의 데이터를 emit하는 publisher가 맞습니다.

Spring MVC가 이미 많은 역할을 수행할 수 있는데 Spring WebFlux가 별도로 존재하는 데는 둘의 차이점을 비교함으로 이해할 수 있을 것입니다.

ReactiveServlet
Netty,Servlet 3.1+Servlet
Reactive Streams AdaptersServlet API
Spring Security ReactiveSpring Security
Spring WebFluxSpring MVC
Mongo,Redis,R2DBC...JDBC,JPA,NoSQL...

이외에도 리액티브Non-blocking 통신을 지원하지만 MVCBlocking통신 방식을 지원합니다. 리액티브는 Non-Blocking을 지원하기 위해 Blocking 될 수 있는 부분들이 모두 Non-Blocking통신이 가능하도록 만들어야 합니다.

Spring MVC와 Spring WebFlux는 에너테이션, 웹 서버를 그대로 사용할 수 있으며 로직이나 DB등에서 다른 구현체를 사용함을 알 수 있습니다.

MVC를 사용할때와 WebFlux를 사용할때 어떻게 다른 지는 간단한 예제를 확인 해봄으로써 조금 더 이해할 수 있을 것 입니다.




SpringMVC, WebFlux 비교

우선 구현하기전 A서버와 B서버를 다음과 같이 가정하겠습니다.

A서버 : 다른 서버로 요청을 보냅니다. MVC인 경우와 WebFlux인 경우 2가지로 나뉘어 보겠습니다.
B서버 : 단순히 A서버에 응답합니다. 응답 직전 5초를 기다립니다.

A서버-애플리케이션 -> A서버-컨트롤러 -> B서버-컨트롤러순으로 호출하여 각각의 동작 결과가 어떻게 다른지 확인하겠습니다.



SpringMVC 방식

@RestController
@RequestMapping("B서버")
public class B서버 {
	@GetMapping("/{URI})
    public ResponseEntity 핸들러메서드(@PathVariable("URI") long id) throws InterruptedException {
    	리턴클래스 리턴객체 = new 리턴클래스(...);
        
        Thread.sleep(5000);
        return ResponseEntity.ok(리턴객체);
    }
}

B서버는 단순 리턴객체를 만들고 5초를 기다린 다음 다시 리턴합니다.

@Slf4j
@SpringBootApplication
public class A서버-Application{
	...
    
    @Bean
    public CommandLineRunner run(){
    	return (String... args) -> {
        	for(int i=0; i<5; i++){
            	리턴클래스 리턴객체 = this.get객체();
                log.info("응답완료");
            }
        };
    }
    
    private 리턴클래스 get객체(){
    	RestTemplate restTemplate = new RestTemplate();
        String uri = "A서버/URI"
        ResonseEntity<리턴클래스> response = restTemplate.getForEntity(uri,리턴클래스.class);
        
        return response.getBody();
    }
}
  • CommandLineRunner : 웹 애플리케이션 실행 시 수행할 작업을 리턴합니다. 단순히 5번 this.get객체()를 호출합니다.
  • get객체() : A서버-컨트롤러를 호출하여 작업을 위임 합니다.
  • A서버/URI : A서버의 컨트롤러를 호출하기위한 URL입니다.
  • RestTemplate : 요청후 응답을 기다리는 동기방식 입니다.
  • getForEntity() : A서버의 핸들러메서드를 호출함으로써 작업을 위임합니다.

A서버-애플리케이션A서버의 컨트롤러에 요청을 전달하는 요청을 수행합니다. 그렇다면 A서버의 컨트롤러도 정의해야 합니다.

@Slf4j
@RestController
@RequestMapping("A서버")
public class A서버-MVC{
	private final RestTemplate restTemplate;
    
    String uri = "B서버/URI"
    public A서버-MVC(RestTemplateBuilder restTemplateBuilder){
    	this.restTemplate = restTemplateBuilder.build();
    }
    
    @GetMapping("{URI}")
    public ResponseEntity 핸들러메서드(@PathVariable("URI") long id){
    	log.info("요청 수신");
    	ResponseEntity<리턴클래스> response = restTeoplate.getForEntity(uri,리턴클래스.class);
        return ResponseEntity.ok(response.getBody());
    }
}
  • RestTemplateBuilder : 스프링 컨테이너에 존재하고, RestTemplate를 반환하는 builder 클래스입니다.
  • uri : B서버를 호출하기 위한 주소입니다.
  • getForEntity() : B서버를 단순히 호출합니다.

순서를 보자면 A서버-애플리케이션 -> A서버-컨트롤러 -> B서버-컨트롤러순으로 호출이 됩니다.

실행결과 로그는 아래와 같습니다.

요청 수신
//5초
응답 완료
요청 수신
//5초
응답 완료
요청 수신
//5초
응답 완료
요청 수신
//5초
응답 완료
요청 수신
//5초
응답 완료

MVC방식은 Blocking방식이기 때문에 요청후 응답을 기다립니다. 그래서 B서버가 5초동안 대기하는동안 A서버도 같이 대기합니다.



WebFlux 방식

이번에는 SpringMVC방식을 WebFlux방식으로 바꾸었을때 위의 결과가 어떻게 달라지는지 확인해보겠습니다.

@RestController
@RequestMapping("B서버")
public class B서버 {
	@ResponseStatus(HttpStatus.OK)
	@GetMapping("/{URI})
    public Mono<리턴클래스> 핸들러메서드(@PathVariable("URI") long id) throws InterruptedException {
    	리턴클래스 리턴객체 = new 리턴클래스(...);
        
        Thread.sleep(5000);
        return Mono.just(리턴객체);
    }
}

기존의 Blocking방식의 ResponseEntity<>를 리턴하던것에서 Non-Blocking통신을 위해 Reacotr의 publisher인 Mono를 리턴합니다.

@Slf4j
@SpringBootApplication
public class A서버-Application{
	...
    
    @Bean
    public CommandLineRunner run(){
    	return (String... args) -> {
        	for(int i=0; i<5; i++){
            	this.get객체()
                	.subscribe(
                    	response -> {
                        	log.info("응답 완료");
                        }
                    );
            }
        };
    }
    
    private Mono<리턴클래스> get객체(){
        String uri = "A서버/URI"
        
        return WebClient.create()
        	.get()
            .uri(uri)
            .retrieve()
            .bodyToMono(리턴클래스.class);
    }
}

A서버-애플리케이션도 마찬가지로 publisher-subscribe구조로 작동할 수 있도록 Mono클래스로 감싸서 리턴합니다.

메서드의 역할은 메서드명으로 기존의 역할들을 직적접으로 해석이 가능하므로 생략하겠습니다.

@Slf4j
@RestController
@RequestMapping("A서버")
public class A서버-WebFlux{    
    String uri = "B서버/URI"

    @ResponseStatus(HttpStatus.OK)
    @GetMapping("{URI}")
    public Mono<리턴클래스> 핸들러메서드(@PathVariable("URI") long id){
    	log.info("요청 수신");
    	return WebClient.create()
        		.get()
                .uri(uri)
                .retrieve()
                .bodyToMono(리턴클래스.class);
    }
}

A서버-애플리케이션 -> A서버-컨트롤러 -> B서버 컨트롤러순으로 호출되고 리턴클래스의 객체를 호출하는것, B서버에서 5초 대기, 출력등은 모두 동일합니다. 다만 기존의 RestTeplate,ResposeEntity로 감싸서 리턴하던 것을 Mono클래스로 감싸서 Non-Blocking통신하는 것만 달라졌습니다.

실행 결과는 아래와 같습니다.

요청 수신
요청 수신
요청 수신
요청 수신
요청 수신
//5초
응답 완료
응답 완료
응답 완료
응답 완료
응답 완료

A서버B서버가 5초 대기하는 것을 기다려 주지 않고 다음 작업을 요청하는 Non-Blocking통신을 하고 있는 것을 확인할 수 있습니다.




후기

더 깊게 학습을 하려면 MVC와 별개로 학습하고 익혀야 하는 내용이 매우 많습니다. 아직은 MVC와는 다른 WebFlux는 이런게 있고 이런식으로 다르게 동작한다 정도로 익혀두는게 좋을 것 같습니다.




GitHub

없음!

profile
오늘도 내일도 화이팅!

0개의 댓글