Rest Client
Rest API 서버에 HTTP 요청(GET, POST, PUT, DELETE 등)을 보낼 수 있는 클라이언트 툴 또는 라이브러리이다.
예시로 UI가 갖춰져 있는 Postman을 떠올릴 수 있겠다.
RestTemplate
Blocking I/O 기반의 Synchronous API이다.
따라서 순차적으로 실행중인 라인이 끝나기 전까지 다음 라인으로 넘어가지 않는다.
spring-boot-starter-web 의존성을 등록하면, RestTemplateAutoConfiguration 이 자동 설정된다. 또, RestTemplateBuilder 를 빈으로 자동 등록해준다.
WebClient
Non-Blocking I/O 기반의 Asynchronous API이다.
WebClientAutoConfiguration 이 자동설정되고, spring-boot-starter-web 이 의존성으로 등록되어 있다면 RestTemplateBuilder를 빈으로 등록해준다.
WebClient 사용을 위해서는 webflux를 추가한다.
RestTemplate / WebClient
@RestController
public class SampleController {
@GetMapping("/hello")
public String hello() throws InterruptedException {
Thread.sleep(3000L);
return "hello";
}
@GetMapping("/sample")
public String sample() throws InterruptedException {
Thread.sleep(5000L);
return "sample";
}
}
@RestController를 구현하고,
각각의 GetMapping은 3초와 5초동안 sleep한다.
1. RestTemplateBuilder를 주입받아 RestTemplate 생성
- getForObject로 get요청 보내기
- blocking i/o : 호출된 함수가 자신의 작업을 모두 마칠 때까지 호출한 함수에게 제어권을 넘겨주지 않고 대기하게 만듦
- sync : 호출된 함수의 작업 완료 여부를 신경쓰기 때문에 작업을 마칠 때까지 기다린다.
@Component
public class RestRunner implements ApplicationRunner {
@Autowired
public 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);
String sampleResult = restTemplate.getForObject("http://localhost:8080/sample", String.class);
stopWatch.stop();
System.out.println(stopWatch.prettyPrint());
}
}
5초 째에 "hello"를 출력하고, 8초 째에 "sample"을 출력한다.
sync-blocking : /hello GET요청이 끝날 때까지 기다리고, /sample GET요청이 끝날 때까지 기다린다.
따라서 두 요청이 모두 끝나려면 8초가 걸린다.
2. WebClient.Builder를 주입받아 WebClient 생성
- get().uri().retrieve().bodyToMono(String.class)로 GET요청 보내기
- Stream API를 사용하기 때문에 subscribe()로 결과를 반환해야 한다.
- non-blocking i/o : 호출된 함수가 바로 결과를 반환하여, 호출한 함수에게 제어권을 바로 넘겨준다.
- async : 호출된 함수의 작업 완료 여부를 신경쓰지 않기 때문에, 작업 완료 시 호출된 함수는 전달받은 콜백을 실행하기만 한다.
@Component
public class RestRunner implements ApplicationRunner {
@Autowired
WebClient.Builder webClientBuilder;
@Override
public void run(ApplicationArguments args) throws Exception {
WebClient webClient = webClientBuilder.build();
StopWatch stopWatch = new StopWatch();
stopWatch.start();
Mono<String> helloResult = webClient.get().uri("http://localhost:8080/hello")
.retrieve()
.bodyToMono(String.class);
helloResult.subscribe(result -> {
System.out.println(result);
if (stopWatch.isRunning()){
stopWatch.stop();
}
System.out.println(stopWatch.prettyPrint());
stopWatch.start();
});
Mono<String> worldResult = webClient.get().uri("http://localhost:8080/sample")
.retrieve()
.bodyToMono(String.class);
worldResult.subscribe(result -> {
System.out.println(result);
if (stopWatch.isRunning()){
stopWatch.stop();
}
System.out.println(stopWatch.prettyPrint());
stopWatch.start();
});
}
}
3초 째에 "hello"를 출력하고, 5초 째에 "sample"을 출력한다.
async-nonblocking : /hello GET요청과 /sample GET요청이 병렬적으로 수행된다.
따라서 두 요청이 모두 끝나려면 5초가 걸린다.
Customizing
1. RestTemplate
RestTemplateBuilder 빈 재정의
- org.apache.httpcomponents:httpclient 의존성 추가 필요
- 마찬가지로 ApplicationContext에서 전역적으로 정의
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication app = new SpringApplication(Application.class);
app.run(args);
}
@Bean
public RestTemplateCustomizer restTemplateCustomizer() {
return new RestTemplateCustomizer() {
@Override
public void customize(RestTemplate restTemplate) {
restTemplate.setRequestFactory(new HttpComponentsClientHttpRequestFactory());
}
};
}
}
2. WebClient
webClientBuilder.build()로 빌드하기 전에 필요한 설정 가능
- baseUrl("http://localhost:8080")
- defaultCookie( )
- defaultHeader( )
글로벌 WebClient 객체 사용하기
- WebClientCustomizer 빈 재정의
- ApplicationContext에서 전역적으로 적용한다.
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication app = new SpringApplication(Application.class);
app.run(args);
}
@Bean
public WebClientCustomizer webClientCustomizer(){
return new WebClientCustomizer() {
@Override
public void customize(WebClient.Builder webClientBuilder) {
webClientBuilder.baseUrl("http://localhost:8080");
}
};
}
}
'Spring' 카테고리의 다른 글
@SpringBootTest / @WebMvcTest (0) | 2023.07.25 |
---|---|
스프링 컨테이너 (Spring Container) (0) | 2023.07.24 |
의존성 주입(Dependency Injection, DI) (0) | 2023.07.23 |
(Spring Boot) AOP(Aspect Oriented Programming)를 이용한 예외처리 (0) | 2023.07.20 |