Spring/Spring Boot

RestTemplate, WebClient

100win10 2020. 7. 13. 01:56

 

 

  • 스프링 부트는 Rest Template을 쉽게 사용할 수 있도록 빈을 등록해준다.
  • 이때 빈은 RestTemplateBuilder를 빈으로 등록해 준다.
  • Builder를 주입받아서 필요시마다 Build를 하고 RestClient를 생성해서 사용할 수 있다.
  • WebClient는 WebClient.Builder를 빈으로 등록해준다.

 

 

RestTemplate과 WebClient의 차이?

 

RestTemplate

 

Blocking I/O 기반의 Synchronous API

순서가 있는 처리

 

WebClient

 

Non-Blocking I/O 기반의 Asynchronous API

순서 없는 처리

 

 

 

 

  • 다음과 같이 "/hello" URI는 5초를 쉬고 "/world" URI는 3초를 쉬는 핸들러를 만들어보자.
  • 그리고 이 API 서버에 클라이언트를 가정하고 RestRunner를 만들자.

 

 

 

  • 다음과 같은 RestRunner는 restTemplateBuilder를 주입받은 후 "/hello"와 "/world"를 호출할 것이다.
  • restTemplate을 통해 해당 결과들을 String 타입으로 바로 받아올 수 있다.

 

 

 

  • restTemplate은 Blocking Synchronous I/O이기 때문에 "/hello"를 마친다음에 "/world"를 가게 된다.
  • 즉 순차 실행이며 메서드가 처리되기 전까지 다음 라인으로 가지 않는다.

 

 

 

 

  • 결과를 보면 5초 후에 helloResult를 출력하고 3초 후에 worldResult를 출력하게 될 것이다.
  • 따라서 총 8초가 걸리게 된다.

 

 

 


WebClient를 살펴보자.

 

  • WebClient를 사용하기 위해서는 webflux 의존성을 넣어주어야 한다.
1
2
3
4
<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-webflux</artifactId>
        </dependency>
cs

 

 

 

 

  • RestRunner을 다음과 같이 바꾸어주자.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
@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();
 
        // TODO /hello
        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();
                });
 
        // TODO /world
        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();
        });
 
        stopWatch.stop();
        System.out.println(stopWatch.prettyPrint());
    }
}
 
 
cs

 

 

 

 

 

 

  • subscribe를 통해 요청을 보내는데 요청을 보내는 동안 응답이 오면 asynchronous 하게 처리가 된다.
  • 따라서 응답처리를 기다리지 않는다. 이는 '/hello' URI가 앞에 있지만 world가 먼저 찍혀서 나온 이유다.