关于Spring WebClient,我有一个问题
在我的应用程序中,我需要执行许多类似的API调用,有时我需要在调用中更改头(身份验证令牌)。因此,问题是,这两种选择有什么更好的:
private final
字段,为MyService.class的所有传入请求创建一个WebClient,类似于下面的代码:WebClient webClient = WebClient.builder() .baseUrl("inf") .defaultHeader(HttpHeaders.CONTENT_TYPE,MediaType.APPLICATION_JSON_VALUE) .defaultHeader(HttpHeaders.ACCEPT,MediaType.APPLICATION_JSON_VALUE) .build();
这里出现了另一个问题: WebClient线程安全吗?(因为许多线程都使用服务)
我想提供最大的性能,并以正确的方式使用它,但我不知道WebClient在其中是如何工作的,以及它期望如何使用。
谢谢。
发布于 2018-03-05 01:52:10
关于WebClient
的两个关键问题
ClientHttpConnector
上配置的WebClient
引用。WebClient
是不可变的考虑到这一点,您应该尝试在应用程序中重用相同的ClientHttpConnector
,因为这将共享连接池--这可以说是性能中最重要的事情。这意味着您应该尝试从同一个WebClient
调用派生所有WebClient.create()
实例。Spring通过为您创建和配置一个WebClient.Builder
bean来帮助您实现这一点,您可以在应用程序中的任何地方插入该bean。
因为WebClient
是不可变的,所以它是线程安全的。WebClient
用于反应性环境,在这种环境中,没有任何东西绑定到特定的线程(这并不意味着不能在传统的Servlet应用程序中使用)。
如果您想改变发出请求的方式,有几种方法可以做到这一点:
在构建器阶段配置东西
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();
发布于 2020-03-03 16:45:05
根据我的经验,如果您在无法控制的服务器上调用外部API,则根本不使用WebClient,或者在关闭池机制时使用它。连接池带来的任何性能收益都被内置在(默认的反应堆-netty)库中的假设大大高估了,这些假设会在一个API调用上造成随机错误,而另一个API调用则被远程主机突然终止,等等。在某些情况下,您甚至不知道错误发生在哪里,因为调用都是从共享工作线程发出的。
我犯了一个使用WebClient的错误,因为RestTemplate的文档说它在将来会被废弃。事后看来,我会使用常规的HttpClient或Apache,但是如果您和我一样并且已经用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()来获取全局资源。您可以手动提供池设置,但考虑到即使在默认设置下也会出现错误,我认为这不值得冒险。
https://stackoverflow.com/questions/49095366
复制