调用 REST 服务
Spring Boot 提供了多种便捷的方法来调用远程 REST 服务。
如果您正在开发一个非阻塞响应式应用程序并且您正在使用 Spring WebFlux,那么您可以使用WebClient.
如果您更喜欢阻止 API,则可以使用RestClient或RestTemplate.
Web客户端
如果你的 Classpath 中有 Spring WebFlux,我们建议你使用WebClient调用远程 REST 服务。
这WebClientinterface 提供了一个函数式风格的 API,并且是完全响应式的。
您可以详细了解WebClient在 Spring Framework 文档的 dedicated 部分。
如果你不编写响应式 Spring WebFlux 应用程序,你可以使用RestClient而不是WebClient.
这提供了类似的功能 API,但 this is blocking instead reactor 。 |
Spring Boot 创建并预配置原型WebClient.BuilderBean 为你。
强烈建议将它注入到您的组件中,并使用它来创建WebClient实例。
Spring Boot 正在配置该构建器以共享 HTTP 资源并以与服务器相同的方式反映编解码器设置(参见 WebFlux HTTP 编解码器自动配置)等等。
以下代码显示了一个典型的示例:
-
Java
-
Kotlin
import reactor.core.publisher.Mono;
import org.springframework.stereotype.Service;
import org.springframework.web.reactive.function.client.WebClient;
@Service
public class MyService {
private final WebClient webClient;
public MyService(WebClient.Builder webClientBuilder) {
this.webClient = webClientBuilder.baseUrl("https://example.org").build();
}
public Mono<Details> someRestCall(String name) {
return this.webClient.get().uri("/{name}/details", name).retrieve().bodyToMono(Details.class);
}
}
import org.springframework.stereotype.Service
import org.springframework.web.reactive.function.client.WebClient
import reactor.core.publisher.Mono
@Service
class MyService(webClientBuilder: WebClient.Builder) {
private val webClient: WebClient
init {
webClient = webClientBuilder.baseUrl("https://example.org").build()
}
fun someRestCall(name: String?): Mono<Details> {
return webClient.get().uri("/{name}/details", name)
.retrieve().bodyToMono(Details::class.java)
}
}
WebClient 运行时
Spring Boot 将自动检测哪个ClientHttpConnector用于驾驶WebClient取决于应用程序 Classpath 上可用的库。
按优先顺序,支持以下客户端:
-
Reactor Netty
-
Jetty RS 客户端
-
Apache HttpClient
-
JDK HttpClient
如果 Classpath 上有多个 Client 端可用,则将使用最首选的 Client 端。
这spring-boot-starter-webfluxStarter 依赖于io.projectreactor.netty:reactor-netty默认情况下,它同时带来 server 和 client 实现。
如果您选择使用 Jetty 作为响应式服务器,则应添加对 Jetty 响应式 HTTP 客户端库的依赖项。org.eclipse.jetty:jetty-reactive-httpclient.
对服务器和客户端使用相同的技术有其优势,因为它会自动在客户端和服务器之间共享 HTTP 资源。
开发人员可以通过提供自定义ReactorResourceFactory或JettyResourceFactorybean - 这将应用于客户端和服务器。
如果您希望为客户端覆盖该选择,您可以定义自己的ClientHttpConnectorbean 并完全控制客户端配置。
全局 HTTP 连接器配置
如果自动检测到ClientHttpConnector不能满足您的需求,您可以使用spring.http.reactiveclient.connector属性来选取特定连接器。
例如,如果您的类路径中有 Reactor Netty,但您更喜欢 Jetty 的HttpClient您可以添加以下内容:
-
Properties
-
YAML
spring.http.reactiveclient.connector=jetty
spring:
http:
reactiveclient:
connector: jetty
您还可以设置属性来更改将应用于所有响应式连接器的默认值。 例如,您可能希望更改超时,如果遵循重定向:
-
Properties
-
YAML
spring.http.reactiveclient.connect-timeout=2s
spring.http.reactiveclient.read-timeout=1s
spring.http.reactiveclient.redirects=dont-follow
spring:
http:
reactiveclient:
connect-timeout: 2s
read-timeout: 1s
redirects: dont-follow
对于更复杂的自定义,您可以使用ClientHttpConnectorBuilderCustomizer或声明你自己的ClientHttpConnectorBuilderbean,这将导致 auto-configuration 回退。
当您需要自定义底层 HTTP 库的某些内部结构时,这可能很有用。
例如,以下将使用配置了特定ProxySelector:
-
Java
-
Kotlin
import java.net.ProxySelector;
import org.springframework.boot.http.client.reactive.ClientHttpConnectorBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration(proxyBeanMethods = false)
public class MyConnectorHttpConfiguration {
@Bean
ClientHttpConnectorBuilder<?> clientHttpConnectorBuilder(ProxySelector proxySelector) {
return ClientHttpConnectorBuilder.jdk().withHttpClientCustomizer((builder) -> builder.proxy(proxySelector));
}
}
import org.springframework.boot.http.client.reactive.ClientHttpConnectorBuilder;
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import java.net.ProxySelector
import java.net.http.HttpClient
@Configuration(proxyBeanMethods = false)
class MyConnectorHttpConfiguration {
@Bean
fun clientHttpConnectorBuilder(proxySelector: ProxySelector): ClientHttpConnectorBuilder<*> {
return ClientHttpConnectorBuilder.jdk().withHttpClientCustomizer { builder -> builder.proxy(proxySelector) }
}
}
WebClient 自定义
有三种主要方法WebClient自定义,具体取决于您希望自定义应用的范围。
要使任何自定义的范围尽可能窄,请注入自动配置的WebClient.Builder然后根据需要调用其方法。WebClient.Builder实例是有状态的:生成器上的任何更改都会反映在随后使用它创建的所有客户端中。
如果要使用同一构建器创建多个客户端,还可以考虑使用WebClient.Builder other = builder.clone();.
要对所有应用程序进行 Additive 自定义WebClient.Builder实例中,你可以声明WebClientCustomizerbeans 并将WebClient.Builder注射点局部。
最后,您可以回退到原始 API 并使用WebClient.create().
在这种情况下,没有自动配置或WebClientCustomizer。
WebClient SSL 支持
如果您需要在ClientHttpConnector由WebClient,您可以注入WebClientSsl实例,该实例可以与构建器的apply方法。
这WebClientSsl接口提供对您在application.properties或application.yaml文件。
以下代码显示了一个典型的示例:
-
Java
-
Kotlin
import reactor.core.publisher.Mono;
import org.springframework.boot.autoconfigure.web.reactive.function.client.WebClientSsl;
import org.springframework.stereotype.Service;
import org.springframework.web.reactive.function.client.WebClient;
@Service
public class MyService {
private final WebClient webClient;
public MyService(WebClient.Builder webClientBuilder, WebClientSsl ssl) {
this.webClient = webClientBuilder.baseUrl("https://example.org").apply(ssl.fromBundle("mybundle")).build();
}
public Mono<Details> someRestCall(String name) {
return this.webClient.get().uri("/{name}/details", name).retrieve().bodyToMono(Details.class);
}
}
import org.springframework.boot.autoconfigure.web.reactive.function.client.WebClientSsl
import org.springframework.stereotype.Service
import org.springframework.web.reactive.function.client.WebClient
import reactor.core.publisher.Mono
@Service
class MyService(webClientBuilder: WebClient.Builder, ssl: WebClientSsl) {
private val webClient: WebClient
init {
webClient = webClientBuilder.baseUrl("https://example.org")
.apply(ssl.fromBundle("mybundle")).build()
}
fun someRestCall(name: String?): Mono<Details> {
return webClient.get().uri("/{name}/details", name)
.retrieve().bodyToMono(Details::class.java)
}
}
Rest客户端
如果您未在应用程序中使用 Spring WebFlux 或 Project Reactor,我们建议您使用RestClient调用远程 REST 服务。
这RestClientinterface 提供功能式的阻塞 API。
Spring Boot 创建并预配置原型RestClient.BuilderBean 为你。
强烈建议将它注入到您的组件中,并使用它来创建RestClient实例。
Spring Boot 正在使用HttpMessageConverters和适当的ClientHttpRequestFactory.
以下代码显示了一个典型的示例:
-
Java
-
Kotlin
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestClient;
@Service
public class MyService {
private final RestClient restClient;
public MyService(RestClient.Builder restClientBuilder) {
this.restClient = restClientBuilder.baseUrl("https://example.org").build();
}
public Details someRestCall(String name) {
return this.restClient.get().uri("/{name}/details", name).retrieve().body(Details.class);
}
}
import org.springframework.boot.docs.io.restclient.restclient.ssl.Details
import org.springframework.stereotype.Service
import org.springframework.web.client.RestClient
@Service
class MyService(restClientBuilder: RestClient.Builder) {
private val restClient: RestClient
init {
restClient = restClientBuilder.baseUrl("https://example.org").build()
}
fun someRestCall(name: String?): Details {
return restClient.get().uri("/{name}/details", name)
.retrieve().body(Details::class.java)!!
}
}
RestClient 自定义
有三种主要方法RestClient自定义,具体取决于您希望自定义应用的范围。
要使任何自定义的范围尽可能窄,请注入自动配置的RestClient.Builder然后根据需要调用其方法。RestClient.Builder实例是有状态的:生成器上的任何更改都会反映在随后使用它创建的所有客户端中。
如果要使用同一构建器创建多个客户端,还可以考虑使用RestClient.Builder other = builder.clone();.
要对所有应用程序进行 Additive 自定义RestClient.Builder实例中,你可以声明RestClientCustomizerbeans 并将RestClient.Builder注射点局部。
最后,您可以回退到原始 API 并使用RestClient.create().
在这种情况下,没有自动配置或RestClientCustomizer。
| 您还可以更改全局 HTTP 客户端配置。 |
RestClient SSL 支持
如果您需要在ClientHttpRequestFactory由RestClient,您可以注入RestClientSsl实例,该实例可以与构建器的apply方法。
这RestClientSsl接口提供对您在application.properties或application.yaml文件。
以下代码显示了一个典型的示例:
-
Java
-
Kotlin
import org.springframework.boot.autoconfigure.web.client.RestClientSsl;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestClient;
@Service
public class MyService {
private final RestClient restClient;
public MyService(RestClient.Builder restClientBuilder, RestClientSsl ssl) {
this.restClient = restClientBuilder.baseUrl("https://example.org").apply(ssl.fromBundle("mybundle")).build();
}
public Details someRestCall(String name) {
return this.restClient.get().uri("/{name}/details", name).retrieve().body(Details.class);
}
}
import org.springframework.boot.autoconfigure.web.client.RestClientSsl
import org.springframework.boot.docs.io.restclient.restclient.ssl.settings.Details
import org.springframework.stereotype.Service
import org.springframework.web.client.RestClient
@Service
class MyService(restClientBuilder: RestClient.Builder, ssl: RestClientSsl) {
private val restClient: RestClient
init {
restClient = restClientBuilder.baseUrl("https://example.org")
.apply(ssl.fromBundle("mybundle")).build()
}
fun someRestCall(name: String?): Details {
return restClient.get().uri("/{name}/details", name)
.retrieve().body(Details::class.java)!!
}
}
如果除了 SSL 捆绑包之外还需要应用其他自定义,则可以使用ClientHttpRequestFactorySettingsclass 替换为ClientHttpRequestFactoryBuilder:
-
Java
-
Kotlin
import java.time.Duration;
import org.springframework.boot.http.client.ClientHttpRequestFactoryBuilder;
import org.springframework.boot.http.client.ClientHttpRequestFactorySettings;
import org.springframework.boot.ssl.SslBundles;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestClient;
@Service
public class MyService {
private final RestClient restClient;
public MyService(RestClient.Builder restClientBuilder, SslBundles sslBundles) {
ClientHttpRequestFactorySettings settings = ClientHttpRequestFactorySettings
.ofSslBundle(sslBundles.getBundle("mybundle"))
.withReadTimeout(Duration.ofMinutes(2));
ClientHttpRequestFactory requestFactory = ClientHttpRequestFactoryBuilder.detect().build(settings);
this.restClient = restClientBuilder.baseUrl("https://example.org").requestFactory(requestFactory).build();
}
public Details someRestCall(String name) {
return this.restClient.get().uri("/{name}/details", name).retrieve().body(Details.class);
}
}
import org.springframework.boot.http.client.ClientHttpRequestFactoryBuilder;
import org.springframework.boot.http.client.ClientHttpRequestFactorySettings;
import org.springframework.boot.ssl.SslBundles
import org.springframework.stereotype.Service
import org.springframework.web.client.RestClient
import java.time.Duration
@Service
class MyService(restClientBuilder: RestClient.Builder, sslBundles: SslBundles) {
private val restClient: RestClient
init {
val settings = ClientHttpRequestFactorySettings.defaults()
.withReadTimeout(Duration.ofMinutes(2))
.withSslBundle(sslBundles.getBundle("mybundle"))
val requestFactory = ClientHttpRequestFactoryBuilder.detect().build(settings);
restClient = restClientBuilder
.baseUrl("https://example.org")
.requestFactory(requestFactory).build()
}
fun someRestCall(name: String?): Details {
return restClient.get().uri("/{name}/details", name).retrieve().body(Details::class.java)!!
}
}
RestTemplate
Spring 框架的RestTemplate类早于RestClient并且是许多应用程序用来调用远程 REST 服务的经典方式。
您可以选择使用RestTemplate当您有不想迁移到的现有代码时RestClient,或者因为您已经熟悉RestTemplate应用程序接口。
因为RestTemplate实例在使用之前通常需要进行自定义,Spring Boot 不提供任何单一的自动配置RestTemplate豆。
但是,它会自动配置RestTemplateBuilder,可用于创建RestTemplate实例。
自动配置的RestTemplateBuilder确保 SensibleHttpMessageConverters和适当的ClientHttpRequestFactory应用于RestTemplate实例。
以下代码显示了一个典型的示例:
-
Java
-
Kotlin
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
@Service
public class MyService {
private final RestTemplate restTemplate;
public MyService(RestTemplateBuilder restTemplateBuilder) {
this.restTemplate = restTemplateBuilder.build();
}
public Details someRestCall(String name) {
return this.restTemplate.getForObject("/{name}/details", Details.class, name);
}
}
import org.springframework.boot.web.client.RestTemplateBuilder
import org.springframework.stereotype.Service
import org.springframework.web.client.RestTemplate
@Service
class MyService(restTemplateBuilder: RestTemplateBuilder) {
private val restTemplate: RestTemplate
init {
restTemplate = restTemplateBuilder.build()
}
fun someRestCall(name: String): Details {
return restTemplate.getForObject("/{name}/details", Details::class.java, name)!!
}
}
RestTemplateBuilder包含许多有用的方法,可用于快速配置RestTemplate.
例如,要添加 BASIC 身份验证支持,您可以使用builder.basicAuthentication("user", "password").build().
RestTemplate 自定义
有三种主要方法RestTemplate自定义,具体取决于您希望自定义应用的范围。
要使任何自定义的范围尽可能窄,请注入自动配置的RestTemplateBuilder然后根据需要调用其方法。
每个方法调用都会返回一个新的RestTemplateBuilder实例,因此自定义项仅影响 Builder 的这种使用。
要进行应用程序范围的增材自定义,请使用RestTemplateCustomizer豆。
所有此类 bean 都会自动注册到自动配置的RestTemplateBuilder并应用于使用它构建的任何模板。
以下示例显示了一个定制器,该定制器为除192.168.0.5:
-
Java
-
Kotlin
import org.apache.hc.client5.http.classic.HttpClient;
import org.apache.hc.client5.http.impl.classic.HttpClientBuilder;
import org.apache.hc.client5.http.impl.routing.DefaultProxyRoutePlanner;
import org.apache.hc.client5.http.routing.HttpRoutePlanner;
import org.apache.hc.core5.http.HttpException;
import org.apache.hc.core5.http.HttpHost;
import org.apache.hc.core5.http.protocol.HttpContext;
import org.springframework.boot.web.client.RestTemplateCustomizer;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;
public class MyRestTemplateCustomizer implements RestTemplateCustomizer {
@Override
public void customize(RestTemplate restTemplate) {
HttpRoutePlanner routePlanner = new CustomRoutePlanner(new HttpHost("proxy.example.com"));
HttpClient httpClient = HttpClientBuilder.create().setRoutePlanner(routePlanner).build();
restTemplate.setRequestFactory(new HttpComponentsClientHttpRequestFactory(httpClient));
}
static class CustomRoutePlanner extends DefaultProxyRoutePlanner {
CustomRoutePlanner(HttpHost proxy) {
super(proxy);
}
@Override
protected HttpHost determineProxy(HttpHost target, HttpContext context) throws HttpException {
if (target.getHostName().equals("192.168.0.5")) {
return null;
}
return super.determineProxy(target, context);
}
}
}
import org.apache.hc.client5.http.classic.HttpClient
import org.apache.hc.client5.http.impl.classic.HttpClientBuilder
import org.apache.hc.client5.http.impl.routing.DefaultProxyRoutePlanner
import org.apache.hc.client5.http.routing.HttpRoutePlanner
import org.apache.hc.core5.http.HttpException
import org.apache.hc.core5.http.HttpHost
import org.apache.hc.core5.http.protocol.HttpContext
import org.springframework.boot.web.client.RestTemplateCustomizer
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory
import org.springframework.web.client.RestTemplate
class MyRestTemplateCustomizer : RestTemplateCustomizer {
override fun customize(restTemplate: RestTemplate) {
val routePlanner: HttpRoutePlanner = CustomRoutePlanner(HttpHost("proxy.example.com"))
val httpClient: HttpClient = HttpClientBuilder.create().setRoutePlanner(routePlanner).build()
restTemplate.requestFactory = HttpComponentsClientHttpRequestFactory(httpClient)
}
internal class CustomRoutePlanner(proxy: HttpHost?) : DefaultProxyRoutePlanner(proxy) {
@Throws(HttpException::class)
public override fun determineProxy(target: HttpHost, context: HttpContext): HttpHost? {
if (target.hostName == "192.168.0.5") {
return null
}
return super.determineProxy(target, context)
}
}
}
最后,您可以定义自己的RestTemplateBuilder豆。
这样做将替换自动配置的生成器。
如果你想要任何RestTemplateCustomizerbean 应用于您的自定义构建器,就像自动配置所做的那样,使用RestTemplateBuilderConfigurer.
以下示例公开了RestTemplateBuilder这与 Spring Boot 的自动配置将执行的作相匹配,只是还指定了自定义连接和读取超时:
-
Java
-
Kotlin
import java.time.Duration;
import org.springframework.boot.autoconfigure.web.client.RestTemplateBuilderConfigurer;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration(proxyBeanMethods = false)
public class MyRestTemplateBuilderConfiguration {
@Bean
public RestTemplateBuilder restTemplateBuilder(RestTemplateBuilderConfigurer configurer) {
return configurer.configure(new RestTemplateBuilder())
.connectTimeout(Duration.ofSeconds(5))
.readTimeout(Duration.ofSeconds(2));
}
}
import org.springframework.boot.autoconfigure.web.client.RestTemplateBuilderConfigurer
import org.springframework.boot.web.client.RestTemplateBuilder
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import java.time.Duration
@Configuration(proxyBeanMethods = false)
class MyRestTemplateBuilderConfiguration {
@Bean
fun restTemplateBuilder(configurer: RestTemplateBuilderConfigurer): RestTemplateBuilder {
return configurer.configure(RestTemplateBuilder()).connectTimeout(Duration.ofSeconds(5))
.readTimeout(Duration.ofSeconds(2))
}
}
最极端(也很少使用)的选项是创建自己的RestTemplateBuilderBean 的 Bean 中。
除了替换自动配置的构建器外,这还可以防止任何RestTemplateCustomizer豆子被使用。
| 您还可以更改全局 HTTP 客户端配置。 |
RestTemplate SSL 支持
如果您需要在RestTemplate中,您可以将 SSL 捆绑包应用于RestTemplateBuilder如以下示例所示:
-
Java
-
Kotlin
import org.springframework.boot.docs.io.restclient.resttemplate.Details;
import org.springframework.boot.ssl.SslBundles;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
@Service
public class MyService {
private final RestTemplate restTemplate;
public MyService(RestTemplateBuilder restTemplateBuilder, SslBundles sslBundles) {
this.restTemplate = restTemplateBuilder.sslBundle(sslBundles.getBundle("mybundle")).build();
}
public Details someRestCall(String name) {
return this.restTemplate.getForObject("/{name}/details", Details.class, name);
}
}
import org.springframework.boot.docs.io.restclient.resttemplate.Details
import org.springframework.boot.ssl.SslBundles
import org.springframework.boot.web.client.RestTemplateBuilder
import org.springframework.stereotype.Service
import org.springframework.web.client.RestTemplate
@Service
class MyService(restTemplateBuilder: RestTemplateBuilder, sslBundles: SslBundles) {
private val restTemplate: RestTemplate
init {
restTemplate = restTemplateBuilder.sslBundle(sslBundles.getBundle("mybundle")).build()
}
fun someRestCall(name: String): Details {
return restTemplate.getForObject("/{name}/details", Details::class.java, name)!!
}
}
RestClient 和 RestTemplate 的 HTTP 客户端检测
Spring Boot 将自动检测要使用的 HTTP 客户端RestClient和RestTemplate取决于应用程序 Classpath 上可用的库。
按优先顺序,支持以下客户端:
-
Apache HttpClient
-
Jetty HttpClient
-
Reactor Netty HttpClient
-
JDK 客户端 (
java.net.http.HttpClient) -
简单 JDK 客户端 (
java.net.HttpURLConnection)
如果 Classpath 上有多个 Client 端可用,并且未提供全局配置,则将使用最首选的 Client 端。
全局 HTTP 客户端配置
如果自动检测到的 HTTP 客户端不能满足您的需求,您可以使用spring.http.client.factory属性来选择特定的工厂。
例如,如果您的类路径中有 Apache HttpClient,但您更喜欢 Jetty 的HttpClient您可以添加以下内容:
-
Properties
-
YAML
spring.http.client.factory=jetty
spring:
http:
client:
factory: jetty
您还可以设置属性以更改将应用于所有客户端的默认值。 例如,您可能希望更改超时,如果遵循重定向:
-
Properties
-
YAML
spring.http.client.connect-timeout=2s
spring.http.client.read-timeout=1s
spring.http.client.redirects=dont-follow
spring:
http:
client:
connect-timeout: 2s
read-timeout: 1s
redirects: dont-follow
对于更复杂的自定义,您可以使用ClientHttpRequestFactoryBuilderCustomizer或声明你自己的ClientHttpRequestFactoryBuilderbean,这将导致 auto-configuration 回退。
当您需要自定义底层 HTTP 库的某些内部结构时,这可能很有用。
例如,以下将使用配置了特定ProxySelector:
-
Java
-
Kotlin
import java.net.ProxySelector;
import org.springframework.boot.http.client.ClientHttpRequestFactoryBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration(proxyBeanMethods = false)
public class MyClientHttpConfiguration {
@Bean
ClientHttpRequestFactoryBuilder<?> clientHttpRequestFactoryBuilder(ProxySelector proxySelector) {
return ClientHttpRequestFactoryBuilder.jdk()
.withHttpClientCustomizer((builder) -> builder.proxy(proxySelector));
}
}
import org.springframework.boot.http.client.ClientHttpRequestFactoryBuilder
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import java.net.ProxySelector
import java.net.http.HttpClient
@Configuration(proxyBeanMethods = false)
class MyClientHttpConfiguration {
@Bean
fun clientHttpRequestFactoryBuilder(proxySelector: ProxySelector): ClientHttpRequestFactoryBuilder<*> {
return ClientHttpRequestFactoryBuilder.jdk()
.withHttpClientCustomizer { builder -> builder.proxy(proxySelector) }
}
}