web-dev-qa-db-ja.com

Spring Boot:非ブロッキング呼び出しと非同期呼び出しを実行するためにRestTemplateの代わりにWebClientを使用する方法

Springboot Resttemplateを使用するspringbootプロジェクトがあります。 1.5.3からspringboot 2.0.1に移動し、WebClientを使用して、残りの呼び出しを非同期にしようとしています。以前は、Resttemplateを使用して受け取った文字列を以下のように処理していました。しかし、WebClientはMonoまたはFluxのデータのみを返します。データを文字列として取得するにはどうすればよいですか。すでにblock()メソッドを試しましたが、非同期呼び出しを行います。

@Retryable(maxAttempts = 4, value = Java.net.ConnectException.class,
           backoff = @Backoff(delay = 3000, multiplier = 2))
public Mono<String> getResponse(String url) {
    return webClient.get().uri(urlForCurrent).accept(APPLICATION_JSON)
                    .retrieve()
                    .bodyToMono(String.class);
}

RestTemplateを使用したデータフローの提示

  1. コントローラはクライアントの呼び出しを受信します
  2. プロバイダーはデータを文字列形式で取得します
  3. プロバイダーは文字列を処理します
  4. データはコントローラーに与えられます

Controller.Java

@RequestMapping(value = traffic/, method = RequestMethod.GET,
                produces = MediaType.APPLICATION_JSON_VALUE)
public String getTraffic(@RequestParam("place") String location) throws InterruptedException, ExecutionException {
    String trafficJSON = Provider.getTrafficJSON(location)
    return trafficJSON;
}

Provider.Java

public String getTrafficJSON(String location) {
    String url = ----;

    ResponseEntity<String> response = dataFetcher.getResponse(url);

    /// RESPONSEBODY IS READ AS STRING AND IT NEEDS TO BE PROCESSED
    if (null != response {
        return parser.transformJSON(response.getBody(), params);
    }

    return null;
}

DataFetcher.Java

@Retryable(maxAttempts = 4,
           value = Java.net.ConnectException.class,
           backoff = @Backoff(delay = 3000, multiplier = 2))
public ResponseEntity<String> getResponse(String url) {
    /* ----------------------- */
    return getRestTemplate().getForEntity(urlForCurrent, String.class);
}
3
Abhi

最初に理解する必要があるのは、.block()を呼び出す必要がある場合は、RestTemplateを使用することです。WebClientを使用しても何も得られません。

WebClientを使用して利益を得たい場合は、事後対応の観点から考える必要があります。リアクティブプロセスは実際には一連のステップであり、各ステップの入力はその前のステップの出力です。リクエストが届くと、コードは一連のステップを作成し、すぐに戻ってhttpスレッドを解放します。次に、フレームワークはワーカースレッドのプールを使用して、前のステップからの入力が利用可能になったときに各ステップを実行します。

利点は、コードの記述方法を再考しなければならないという小さなコストで、競合する要求を受け入れる能力が大幅に向上することです。アプリケーションに必要なのは、httpスレッドの非常に小さなプールと、ワーカースレッドの別の非常に小さなプールだけです。

コントローラーメソッドがMonoまたはFluxを返す場合、それは正しく行われており、block()を呼び出す必要はありません。

このような最も単純な形式は次のとおりです。

@GetMapping(value = "endpoint", produces = MediaType.TEXT_PLAIN_VALUE)
@ResponseBody
@ResponseStatus(OK)
public Mono<String> controllerMethod() {

    final UriComponentsBuilder builder =
            UriComponentsBuilder.fromHttpUrl("http://base.url/" + "endpoint")
                    .queryParam("param1", "value");

    return webClient
            .get()
            .uri(builder.build().encode().toUri())
            .accept(APPLICATION_JSON_UTF8)
            .retrieve()
            .bodyToMono(String.class)
            .retry(4)
            .doOnError(e -> LOG.error("Boom!", e))
            .map(s -> {

                // This is your transformation step. 
                // Map is synchronous so will run in the thread that processed the response. 
                // Alternatively use flatMap (asynchronous) if the step will be long running. 
                // For example, if it needs to make a call out to the database to do the transformation.

                return s.toLowerCase();
            });
}

事後対応型の考え方に移行することは、かなり大きなパラダイムシフトですが、努力する価値は十分にあります。アプリケーション全体にブロックコードがまったくない状態に頭を悩ませることができれば、それほど難しくはありません。ステップを作成して返してください。次に、フレームワークにステップの実行を管理させます。

このいずれかが明確でない場合は、より多くのガイダンスを提供させていただきます。

楽しんでください:)

1
Captain