[Spring Boot #18] 스프링 부트 RestTemplate, WebClient
- 📚 Spring/Spring Boot
- 2020. 6. 9. 18:03
Spring 프로젝트를 진행하면서 컴포넌트 내부에서 URL을 요청해야하는 경우가 생긴다.
Spring에서는 Http 요청을 간단하게 이용할 수 있도록 Blocking I/O 기반의 RestTemplate, Non-Blocking I/O 기반의 WebClient 모듈을 제공한다.
| RestTemplate 예제
SampleController.java
package com.kyhslam;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class SampleController {
@GetMapping("/hello")
public String hello() throws InterruptedException{
Thread.sleep(5000l);
return "hello";
}
@GetMapping("/world")
public String world() throws InterruptedException{
Thread.sleep(3000l);
return "world";
}
}
package com.kyhslam;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.stereotype.Component;
import org.springframework.util.StopWatch;
import org.springframework.web.client.RestTemplate;
import reactor.core.publisher.Mono;
@Component
public class RestRunner implements ApplicationRunner {
@Autowired
RestTemplateBuilder restTemplateBuilder;
@Override
public void run(ApplicationArguments args) throws Exception {
RestTemplate restTemplate = restTemplateBuilder.build();
StopWatch stopWatch = new StopWatch();
stopWatch.start();
String helloResult = restTemplate.getForObject("http://localhost:8080/hello", String.class);
System.out.println(helloResult);
String worldResult = restTemplate.getForObject("http://localhost:8080/world", String.class);
System.out.println(worldResult);
stopWatch.stop();
System.out.println(stopWatch.prettyPrint());
}
}
결과
hello
world
StopWatch '': running time = 8176594200 ns
---------------------------------------------
ns % Task name
---------------------------------------------
8176594200 100%
-
RestTemplate 은 Blocking I/O 기반이기 때문에 helloResult 부문이 끝나야지만 다음 worldResult 부분을 실행할 수 있다.
-
즉, 약 8초 정도 지나서 모든 요청을 끝마진다.
| WebFlux (WebClient) 예제
WebFlux 사용을 위해 pom.xml에 webflux dependency 를 추가해 줘야 된다.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
RestRunner.java
package com.kyhslam;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;
import org.springframework.util.StopWatch;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Mono;
@Component
public class RestRunner implements ApplicationRunner {
@Autowired
WebClient.Builder builder;
@Override
public void run(ApplicationArguments args) throws Exception {
WebClient webClient = builder.build();
StopWatch stopWatch = new StopWatch();
stopWatch.start();
Mono<String> helloMono = webClient.get().uri("http://localhost:8080/hello").retrieve().bodyToMono(String.class);
helloMono.subscribe(s -> {
System.out.println(s);
if (stopWatch.isRunning()) {
stopWatch.stop();
}
System.out.println(stopWatch.prettyPrint());
stopWatch.start();
});
Mono<String> worldMono = webClient.get().uri("http://localhost:8080/world").retrieve().bodyToMono(String.class);
worldMono.subscribe(s -> {
System.out.println(s);
if (stopWatch.isRunning()) {
stopWatch.stop();
}
System.out.println(stopWatch.prettyPrint());
stopWatch.start();
});
}
}
실행결과
world
StopWatch '': running time = 4863490900 ns
---------------------------------------------
ns % Task name
---------------------------------------------
4863490900 100%
hello
StopWatch '': running time = 6815297700 ns
---------------------------------------------
ns % Task name
---------------------------------------------
4863490900 071%
1951806800 029%
-
WebClient은 Non-Blocking 기반이기 때문에 각 http 요청이 비동기적으로 발생하게 된다.
-
따라서 위의 RestTemplate를 이용하여 http 요청을 진행햇을 때와 다르게 동작하게 되며 약 8초 정도가 걸리는게 아니고 각 4초, 6초 걸리는 Http 요청을 동시에 처리하게 된다.
-
Mono는 WebClient의 결과를 0 또는 1개의 결과를 받는 추상클래스이며 Publisher 인터페이스를 구현하여 작성되었다. 이 Publisher는 바로 로직을 실행하는 것이 아닌 subscribe 메서드를 통해 결과를 받아올 코드가 실행될 시 그때서야 로직을 실행하게 된다.
'📚 Spring > Spring Boot' 카테고리의 다른 글
[Spring Boot #20] 스프링부트 레디스(Redis) 연동 (0) | 2020.07.26 |
---|---|
[Spring Boot #19] Lombok 정리 (0) | 2020.06.27 |
[Spring Boot #17] 스프링 PostgreSQL 연동 (Docker 활용) (0) | 2020.06.04 |
[Spring Boot #16] 스프링 ExceptionHandler (0) | 2020.05.14 |
[Spring Boot #15] 스프링 웹 MVC - HtmlUnit 써보기 (0) | 2020.05.04 |