调用 REST 服务

Spring Boot 提供了多种便捷方式用于调用远程 REST 服务。 如果你正在开发非阻塞的响应式应用,并且使用 Spring WebFlux,则可以使用 WebClient。 如果你更倾向于阻塞式 API,则可以使用 RestClientRestTemplate

WebClient

如果你的 classpath 上有 Spring WebFlux,推荐使用 WebClient 调用远程 REST 服务。 WebClient 接口提供了函数式风格 API,并且完全响应式。 你可以在专门的 Spring Framework 文档 WebClient 部分 了解更多。

如果你不是在编写响应式 Spring WebFlux 应用,可以使用 RestClient 替代 WebClient。 这提供了类似的函数式 API,但为阻塞式而非响应式。

Spring Boot 会为你创建并预配置一个原型 WebClient.Builder bean。 强烈建议在你的组件中注入它,并用来创建 WebClient 实例。 Spring Boot 配置该 builder 以共享 HTTP 资源,并以与服务器相同的方式反映 codecs 设置(参见 WebFlux HTTP codecs 自动配置),以及更多。

以下代码展示了一个典型示例:

  • 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 会根据应用 classpath 上可用的库自动检测用于驱动 WebClientClientHttpConnector。 优先顺序如下,支持以下客户端:

  1. Reactor Netty

  2. Jetty RS client

  3. Apache HttpClient

  4. JDK HttpClient

如果 classpath 上有多个客户端,将使用优先级最高的客户端。

spring-boot-starter-webflux starter 默认依赖 io.projectreactor.netty:reactor-netty,它同时带来服务器和客户端实现。 如果你选择使用 Jetty 作为响应式服务器,则应添加 Jetty Reactive HTTP client 库依赖 org.eclipse.jetty:jetty-reactive-httpclient。 客户端和服务器使用同一技术有优势,因为会自动在客户端和服务器之间共享 HTTP 资源。

开发者可以通过提供自定义 ReactorResourceFactoryJettyResourceFactory bean 覆盖 Jetty 和 Reactor Netty 的资源配置——这会同时应用于客户端和服务器。

如果你希望为客户端覆盖该选择,可以定义自己的 ClientHttpConnector bean,并完全控制客户端配置。

全局 HTTP Connector 配置

如果自动检测到的 ClientHttpConnector 不能满足你的需求,可以使用 spring.http.reactiveclient.connector 属性选择特定 connector。 例如,如果你的 classpath 上有 Reactor Netty,但更喜欢 Jetty 的 HttpClient,可以添加如下配置:

  • Properties

  • YAML

spring.http.reactiveclient.connector=jetty
spring:
  http:
    reactiveclient:
      connector: jetty

你还可以设置属性以更改所有响应式 connector 的默认值。 例如,你可能希望更改超时时间以及是否跟随重定向:

  • 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,或声明你自己的 ClientHttpConnectorBuilder bean,这将导致自动配置失效。 当你需要定制底层 HTTP 库的一些内部细节时,这很有用。

例如,以下配置将使用带有特定 ProxySelector 的 JDK 客户端:

  • 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 实例是有状态的:对 builder 的任何更改都会反映到随后用它创建的所有客户端。 如果你想用同一个 builder 创建多个客户端,也可以通过 WebClient.Builder other = builder.clone(); 克隆 builder。

若希望对所有 WebClient.Builder 实例进行应用级别的增量定制,可以声明 WebClientCustomizer bean,并在注入点本地更改 WebClient.Builder

最后,你可以回退到原始 API,直接使用 WebClient.create()。 此时不会应用自动配置或 WebClientCustomizer

WebClient SSL 支持

如果你需要对 WebClient 使用的 ClientHttpConnector 进行自定义 SSL 配置,可以注入 WebClientSsl 实例,并结合 builder 的 apply 方法使用。

WebClientSsl 接口可访问你在 application.propertiesapplication.yaml 文件中定义的任意 SSL bundles

以下代码展示了一个典型示例:

  • 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)
	}

}

RestClient

如果你的应用未使用 Spring WebFlux 或 Project Reactor,推荐使用 RestClient 调用远程 REST 服务。

RestClient 接口提供了函数式风格的阻塞式 API。

Spring Boot 会为你创建并预配置一个原型 RestClient.Builder bean。 强烈建议在你的组件中注入它,并用来创建 RestClient 实例。 Spring Boot 会用 HttpMessageConverters 和合适的 ClientHttpRequestFactory 配置该 builder。

以下代码展示了一个典型示例:

  • 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 实例是有状态的:对 builder 的任何更改都会反映到随后用它创建的所有客户端。 如果你想用同一个 builder 创建多个客户端,也可以通过 RestClient.Builder other = builder.clone(); 克隆 builder。

若希望对所有 RestClient.Builder 实例进行应用级别的增量定制,可以声明 RestClientCustomizer bean,并在注入点本地更改 RestClient.Builder

最后,你可以回退到原始 API,直接使用 RestClient.create()。 此时不会应用自动配置或 RestClientCustomizer

你也可以更改 全局 HTTP 客户端配置

RestClient SSL 支持

如果你需要对 RestClient 使用的 ClientHttpRequestFactory 进行自定义 SSL 配置,可以注入 RestClientSsl 实例,并结合 builder 的 apply 方法使用。

RestClientSsl 接口可访问你在 application.propertiesapplication.yaml 文件中定义的任意 SSL bundles

以下代码展示了一个典型示例:

  • 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 bundle 还需要应用其他定制,可以结合 ClientHttpRequestFactorySettingsClientHttpRequestFactoryBuilder 使用:

  • 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 Framework 的 RestTemplate 类早于 RestClient,是许多应用调用远程 REST 服务的经典方式。 当你有现有代码不想迁移到 RestClient,或已熟悉 RestTemplate API 时,可以选择使用 RestTemplate

由于 RestTemplate 实例通常需要在使用前定制,Spring Boot 不会提供任何单一自动配置的 RestTemplate bean。 但会自动配置一个 RestTemplateBuilder,可用于按需创建 RestTemplate 实例。 自动配置的 RestTemplateBuilder 确保为 RestTemplate 实例应用合理的 HttpMessageConverters 和合适的 ClientHttpRequestFactory

以下代码展示了一个典型示例:

  • 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。 所有此类 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 bean。 这样会替换自动配置的 builder。 如果你希望像自动配置一样应用所有 RestTemplateCustomizer bean,可使用 RestTemplateBuilderConfigurer 进行配置。 以下示例暴露了一个与 Spring Boot 自动配置一致但指定了自定义连接和读取超时的 RestTemplateBuilder

  • 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))
	}

}

最极端(且很少用)的方式是创建自己的 RestTemplateBuilder bean 而不使用 configurer。 这不仅会替换自动配置的 builder,还会阻止任何 RestTemplateCustomizer bean 被使用。

你也可以更改 全局 HTTP 客户端配置

RestTemplate SSL 支持

如果你需要对 RestTemplate 进行自定义 SSL 配置,可以如本例所示将 SSL bundle 应用于 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 会根据应用 classpath 上可用的库自动检测用于 RestClientRestTemplate 的 HTTP 客户端。 优先顺序如下,支持以下客户端:

  1. Apache HttpClient

  2. Jetty HttpClient

  3. Reactor Netty HttpClient

  4. JDK client (java.net.http.HttpClient)

  5. Simple JDK client (java.net.HttpURLConnection)

如果 classpath 上有多个客户端,且未提供全局配置,将使用优先级最高的客户端。

全局 HTTP 客户端配置

如果自动检测到的 HTTP 客户端不能满足你的需求,可以使用 spring.http.client.factory 属性选择特定 factory。 例如,如果你的 classpath 上有 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,或声明你自己的 ClientHttpRequestFactoryBuilder bean,这将导致自动配置失效。 当你需要定制底层 HTTP 库的一些内部细节时,这很有用。

例如,以下配置将使用带有特定 ProxySelector 的 JDK 客户端:

  • 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) }
	}

}