Spring HTTP 요청 RestTemplate과 WebClient
Spring은 HTTP 통신을 위해 RestTemplate와 WebClient를 제공한다.
Spring5에서 WebClient가 추가 되면서 RestTemplate는 Deprecated 될 예정이므로 WebClient 사용을 권장한다.
RestTemplate 과 WebClient 차이
RestTemplate
Blocking I/O 기반의 동기식(Synchronous) API
순차적 처리
호출자 Thread를 사용합니다. 별도의 Thread를 할당 하지 않을 경우 Main Thread 사용
RestTemplate 호출에 응답을 받을 때 까지 Thread가 대기상태(block)가 된다.
WebClient
Non-Blocking I/O 기반의 비동기식 API
비순차적 처리
별도의 Worker Thread가 할당된다.
응답을 기다리지 않기 때문에 Thread를 block 시키지 않는다.
예제
아래 rest api를 호출하면 넘어온 파라메터 값만큼 스레드를 멈춘 후 반환 합니다.
@GetMapping("/hello")
public ResponseEntity getHello(Integer millis) throws InterruptedException {
Thread.sleep(millis);
return ResponseEntity.ok("Hello"+millis);
}
RestTemplate
restTemplate의 호출 응답을 받을 경우에만 아래 코드가 실행된다.
public void run(ApplicationArguments args) {
RestTemplate restTemplate = new RestTemplate();
StopWatch stopWatch = new StopWatch();
logger.debug("RestTemplate start");
stopWatch.start();
String one = restTemplate.getForObject(url + "?millis=3000", String.class);
logger.debug("api response one: {}", one);
String two = restTemplate.getForObject(url + "?millis=5000", String.class);
logger.debug("api response two: {}", two);
stopWatch.stop();
logger.debug("restTemplate total sec: {}", stopWatch.getTotalTimeSeconds());
}
호출 결과
WebClient
webClient의 호출 후 Mono 객체를 반환하고 나머지 코드를 실행한다.
응답을 처리 하기 위해 worker thread를 사용하게 된다.
subscribe 메소드를 통해 실제 요청을 하고 응답을 처리하게 됩니다. 응답이 오면 subscribe의 콜백함수가 동작을 합니다.
각 5초, 3초를 파라메터로 전달해 api를 호출하면 별도의 thread로 처리 하기 때문에 소요시간이 3초인 api응답이 먼저 반환되어 처리된다.
block 메소드를 사용하면 blocking 방식으로 동작이 가능하다.
@Override
public void run(ApplicationArguments args) {
WebClient webClient = WebClient.create();
StopWatch stopWatch = new StopWatch();
logger.debug("WebClient start");
stopWatch.start();
Mono<String> one = webClient
.get()
.uri(url + "?millis=5000")
.retrieve()
.bodyToMono(String.class);
one.subscribe(x ->
logger.debug("api response one: {}", x));
Mono<String> two = webClient
.get()
.uri(url + "?millis=3000")
.retrieve()
.bodyToMono(String.class);
two.subscribe(x -> logger.debug("api response two: {}", x));
stopWatch.stop();
logger.debug("webclient total sec: {}", stopWatch.getTotalTimeSeconds());
}
호출 결과