...
WebClient at the other hand is based on the Spring Reactive framework which provides capability to non-blocking async calls thanks to it's event-driven architecture. Because of this WebClient uses less resources (threads, memory).
Affected classes
Apart from the *Spec files the RestTemplate is used only in 2 classes: NcmpConfiguration and DmiRestClient.
The first class configures the client while the second performs requests with RestClient.
These two classes have to be rewritten/refactored to use the WebClient.
Example configuration
Code Block | ||||||||
---|---|---|---|---|---|---|---|---|
| ||||||||
@Slf4j @Configuration @AllArgsConstructor public class WebClientConfiguration { public static final int TIMEOUT = 2000; private final DmiConfiguration.SdncProperties sdncProperties; @Bean public WebClient webClient() { final var httpClient = HttpClient.create() .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, TIMEOUT) // millis .doOnConnected(connection -> connection .addHandlerLast(new ReadTimeoutHandler(TIMEOUT, TimeUnit.MILLISECONDS)) // millis .addHandlerLast(new WriteTimeoutHandler(TIMEOUT, TimeUnit.MILLISECONDS))); //millis return WebClient.builder() .baseUrl(sdncProperties.getBaseUrl()) .defaultHeaders(header -> header.set(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)) .defaultHeaders(header -> header.setBasicAuth(sdncProperties.getAuthUsername(), sdncProperties.getAuthPassword())) .clientConnector(new ReactorClientHttpConnector(httpClient)) .filter(logRequest()) .filter(logResponse()) .build(); } private ExchangeFilterFunction logRequest() { return (clientRequest, next) -> { log.info("Request: {} {}", clientRequest.method(), clientRequest.url()); log.info("--- Http Headers: ---"); clientRequest.headers().forEach(this::logHeader); log.info("--- Http Cookies: ---"); clientRequest.cookies().forEach(this::logHeader); return next.exchange(clientRequest); }; } private ExchangeFilterFunction logResponse() { return ExchangeFilterFunction.ofResponseProcessor(clientResponse -> { log.info("Response: {}", clientResponse.statusCode()); clientResponse.headers().asHttpHeaders() .forEach((name, values) -> values.forEach(value -> log.info("{}={}", name, value))); return Mono.just(clientResponse); }); } private void logHeader(String name, List values) { values.forEach(value -> log.info("{}={}", name, value)); } } |
...
Code Block | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|
| ||||||||||
String response = webClient .get() .uri(resourceUrl) .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) .retrieve() .onStatus(HttpStatus::is4xxClientError, error -> Mono.error(new RuntimeException("API not found"))) .onStatus(HttpStatus::is5xxServerError, error -> Mono.error(new RuntimeException("Server is not responding"))) .bodyToMono(String.class) .block(); return ResponseEntity.ok(response); |
...
Async call example with
...
subscription
Code Block | ||||||||
---|---|---|---|---|---|---|---|---|
| ||||||||
public Mono<String> httpOperationWithJsonData(final HttpMethod httpMethod, final String resourceUrl, final String jsonData, final HttpHeaders httpHeaders) { return webClient .get() .uri(resourceUrl) .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) .retrieve() .onStatus(HttpStatus::is4xxClientError, error -> Mono.error(new RuntimeException("API not found"))) .onStatus(HttpStatus::is5xxServerError, error -> Mono.error(new RuntimeException("Server is not responding"))) .bodyToMono(String.class); } |
...