Spring WebClientについて質問があります。
私のアプリケーションでは、多くの同様のAPI呼び出しを行う必要があります。呼び出しのヘッダーを変更する必要がある場合があります(認証トークン)。したがって、問題が発生します。2つのオプションのどちらが優れているでしょうか。
MyService.classへのすべての受信リクエストに対して1つのWebClientを作成するには、それをprivate final
フィールド、以下のコードのような:
private final WebClient webClient = WebClient.builder()
.baseUrl("https://another_Host.com/api/get_inf")
.defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
.defaultHeader(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE)
.build();
ここで別の質問が発生します:WebClientはスレッドセーフですか? (サービスは多くのスレッドで使用されるため)
最大のパフォーマンスを提供し、正しい方法で使用したいのですが、その中でWebClientがどのように機能するのか、またWebClientがどのように使用されるのかを知りません。
ありがとうございました。
WebClient
に関する2つの重要な点:
ClientHttpConnector
で構成できるWebClient
によって参照される、基礎となるライブラリによって管理されますWebClient
は不変ですこれを念頭に置いて、アプリケーション全体で同じClientHttpConnector
を再利用するようにしてください。これにより、接続プールが共有されます。これは、おそらくパフォーマンスにとって最も重要なことです。つまり、同じWebClient.create()
呼び出しからすべてのWebClient
インスタンスを派生させる必要があります。 Spring Bootは、WebClient.Builder
Bean。アプリのどこにでも挿入できます。
WebClient
は不変であるため、スレッドセーフです。 WebClient
は、特定のスレッドに何も関連付けられていないリアクティブ環境で使用するためのものです(これは、従来のサーブレットアプリケーションで使用できないことを意味するものではありません)。
リクエストの作成方法を変更したい場合は、いくつかの方法で実現できます。
WebClient baseClient = WebClient.create().baseUrl("https://example.org");
Mono<ClientResponse> response = baseClient.get().uri("/resource")
.header("token", "secret").exchange();
// mutate() will *copy* the builder state and create a new one out of it
WebClient authClient = baseClient.mutate()
.defaultHeaders(headers -> {headers.add("token", "secret");})
.build();
それはすべきではありません:
WebClient wc = WebClient
.builder()
.baseUrl(SERER_Origin)
.build();
代わりに
WebClient wc = WebClient.create().baseUrl("https://example.org");
?
私の経験では、制御できないサーバーで外部APIを呼び出す場合は、WebClientをまったく使用しないか、プーリングメカニズムをオフにして使用します。接続プーリングによるパフォーマンスの向上は、(デフォルトのreactor-netty)ライブラリに組み込まれている仮定によって大きく補われます。これにより、あるAPI呼び出しがリモートホストによって突然終了したときに、別のAPI呼び出しでランダムエラーが発生します。場合によっては、呼び出しはすべて共有ワーカースレッドから行われるため、エラーが発生した場所もわかります。
RestTemplateのドキュメントには将来廃止される予定があると記載されているため、WebClientの使用を間違えました。後から考えると、通常のHttpClientまたはApache Commons HttpClientを使用しますが、私と同じで、すでにWebClientで実装されている場合は、次のようにWebClientを作成してプールをオフにすることができます。
private WebClient createWebClient(int timeout) {
TcpClient tcpClient = TcpClient.newConnection();
HttpClient httpClient = HttpClient.from(tcpClient)
.tcpConfiguration(client -> client.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, timeout * 1000)
.doOnConnected(conn -> conn.addHandlerLast(new ReadTimeoutHandler(timeout))));
return WebClient.builder()
.clientConnector(new ReactorClientHttpConnector(httpClient))
.build();
}
***別個のWebClientを作成しても、WebClientが別個の接続プールを持つことにはなりません。 HttpClient.createのコードを見てください。HttpResources.get()を呼び出してグローバルリソースを取得します。プール設定を手動で指定することもできますが、デフォルトのセットアップでも発生するエラーを考慮して、リスクに見合う価値があるとは考えていません。