Spring 서버에서 http 요청을 보내기 위한 방법은 여러가지가 있는데 (Apache HTTP 컴포넌트 인 HttpClient / Spring Framework 에서 지원하는 RestTemplate) 기존 Spring 개발자들이 제일 많이 사용하던 RestTemplate 이 Spring 에서 공식적으로 향후 deprecated 될 예정이므로 보다 현대적인 WebClient 를 사용하라고 권장하였기 때문에 도입
리액티브 프로그래밍 에서 사용하기 위한 웹 호출 인터페이스.
멀티스레드를 지원함.
비동기 처리
리턴타입 변환 T → Mono, Flux
컨트롤러와 서비스 메소드에서의 리턴 타입을 전환하였다. 기존에 일반 타입으로 반환하였다면, Reactor는 리액티브 스트림을 지원하는 Mono와 Flux를 제공하기에 리턴 타입도 Mono, Flux로 전환되어야 한다.
리액티브 라이브러리의 경우 이미 Mono와 Flux의 리턴타입을 가질것이며, 직접 데이터를 생성하는 경우라면 just()
메서드로 감싸서 전달하도록 한다.
비동기 작업의 순서유지를 위해 flatMap 으로 체이닝
WebFlux 전환 시, 내부엔 블로킹이 존재하지 않는다. 작업들은 비동기적으로 처리될 것이며 라인 순서에 따른 실제 코드의 동작 순서는 일치하지 않게된다(메서드를 호출해도 실제 동작은 나중에 처리될것이기 때문이다). 이때 flatMap을 통해 이전 비동기 작업이 끝난 후 다음 로직들이 처리되도록 순서를 보장시켜줄 수 있다.
내부가 동기적인 동작이라면 map 으로 체이닝
flatMap과 map의 차이점은 전달하는 함수의 리턴 타입이다. flatMap에 전달하는 함수의 리턴 타입은 Mono나 Flux와 같은 리액티브 API이며, 이는 비동기 동작이 있는 함수를 전달하기 위해서이다.
하지만, 블로킹될 일이 없는 로직으로만 구성되고 데이터를 직접 생성한다면 map 함수를 통해 체이닝 할 수 있다. 그렇기에 map에 전달하는 함수는 일반적인 오브젝트(T)를 리턴 한다
@Slf4j
@RestController
public class TestController() {
private final TestService testService;
public TestController(Testservice testService) {
this.testService = testService;
}
@GetMapping("/test")
public Mono<TestDTO> test() {
log.info("START");
Mono<TestDTO> dto = testService.test();
log.info("END");
return dto;
}
}
@Service
public class TestService() {
private final WebClient webClient;
private final String baseUrl = "<http://localhost:8080>";
public TestService(WebClient.Builder webClientBuilder) {
this.webClient = webClientBuilder
.baseUrl(baseUrl)
.build();
}
public Mono<TestDTO> test() {
for (int i = 0; i < 100; i++) {
int finalI = i;
req().subscribe(driverDto ->
System.out.println("driverDto.getId() = " + driverDto.getId() + " @@@ " + finalI));
}
return webClient.get()
.uri("/test/" + 2000000118)
.exchangeToMono(response -> {
if (response.statusCode().equals(HttpStatus.OK)) {
System.out.println("DriverService.test @@@ GET");
return response.bodyToMono(DriverDto.class);
} else {
return Mono.empty();
}
});
}
private Mono<TestDTO> seq() {
return webClient.get()
.uri("/test/" + 2000000118)
.accept(MediaType.APPLICATION_JSON)
.exchangeToMono(response -> {
if (response.statusCode().equals(HttpStatus.OK)) {
return response.bodyToMono(DriverDto.class);
} else {
return Mono.empty();
}
});
}
}
→ 결과
TestService
의 for 문에 req() 실행https://devsh.tistory.com/ https://ckddn9496.tistory.com/158 https://velog.io/@jaepani5015/WebClient