Browse Source

Support virtual threading with JDK HTTP clients

Update JDK HTTP Clients so that the use virtual threads when
`Threading.VIRTUAL` is active.

See gh-46404

Signed-off-by: Sangmin Park <sangmins930@gmail.com>
pull/46927/head
Sangmin Park 7 months ago committed by Phillip Webb
parent
commit
e32e3359c2
  1. 7
      module/spring-boot-http-client/src/main/java/org/springframework/boot/http/client/JdkClientHttpRequestFactoryBuilder.java
  2. 20
      module/spring-boot-http-client/src/main/java/org/springframework/boot/http/client/autoconfigure/HttpClientAutoConfiguration.java

7
module/spring-boot-http-client/src/main/java/org/springframework/boot/http/client/JdkClientHttpRequestFactoryBuilder.java

@ -19,6 +19,7 @@ package org.springframework.boot.http.client; @@ -19,6 +19,7 @@ package org.springframework.boot.http.client;
import java.net.http.HttpClient;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.Executors;
import java.util.function.Consumer;
import org.jspecify.annotations.Nullable;
@ -75,6 +76,12 @@ public final class JdkClientHttpRequestFactoryBuilder @@ -75,6 +76,12 @@ public final class JdkClientHttpRequestFactoryBuilder
this.httpClientBuilder.withCustomizer(httpClientCustomizer));
}
public JdkClientHttpRequestFactoryBuilder enableVirtualThreadExecutor() {
return this.withHttpClientCustomizer(builder ->
builder.executor(Executors.newVirtualThreadPerTaskExecutor())
);
}
@Override
protected JdkClientHttpRequestFactory createClientHttpRequestFactory(ClientHttpRequestFactorySettings settings) {
HttpClient httpClient = this.httpClientBuilder.build(asHttpClientSettings(settings.withReadTimeout(null)));

20
module/spring-boot-http-client/src/main/java/org/springframework/boot/http/client/autoconfigure/HttpClientAutoConfiguration.java

@ -24,10 +24,13 @@ import org.springframework.boot.autoconfigure.AutoConfiguration; @@ -24,10 +24,13 @@ import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnThreading;
import org.springframework.boot.autoconfigure.ssl.SslAutoConfiguration;
import org.springframework.boot.autoconfigure.thread.Threading;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.http.client.ClientHttpRequestFactoryBuilder;
import org.springframework.boot.http.client.ClientHttpRequestFactorySettings;
import org.springframework.boot.http.client.JdkClientHttpRequestFactoryBuilder;
import org.springframework.boot.ssl.SslBundles;
import org.springframework.boot.util.LambdaSafe;
import org.springframework.context.annotation.Bean;
@ -64,18 +67,31 @@ public final class HttpClientAutoConfiguration implements BeanClassLoaderAware { @@ -64,18 +67,31 @@ public final class HttpClientAutoConfiguration implements BeanClassLoaderAware {
@Bean
@ConditionalOnMissingBean
ClientHttpRequestFactoryBuilder<?> clientHttpRequestFactoryBuilder(
@ConditionalOnThreading(Threading.PLATFORM)
ClientHttpRequestFactoryBuilder<?> clientHttpRequestFactoryBuilderOnPlatform(
ObjectProvider<ClientHttpRequestFactoryBuilderCustomizer<?>> clientHttpRequestFactoryBuilderCustomizers) {
ClientHttpRequestFactoryBuilder<?> builder = this.factories.builder(this.beanClassLoader);
return customize(builder, clientHttpRequestFactoryBuilderCustomizers.orderedStream().toList());
}
@Bean
@ConditionalOnMissingBean
@ConditionalOnThreading(Threading.VIRTUAL)
ClientHttpRequestFactoryBuilder<?> clientHttpRequestFactoryBuilderOnVirtual(
ObjectProvider<ClientHttpRequestFactoryBuilderCustomizer<?>> clientHttpRequestFactoryBuilderCustomizers) {
ClientHttpRequestFactoryBuilder<?> builder = this.factories.builder(this.beanClassLoader);
if (builder instanceof JdkClientHttpRequestFactoryBuilder jdk) {
return customize(jdk.enableVirtualThreadExecutor(), clientHttpRequestFactoryBuilderCustomizers.orderedStream().toList());
}
return customize(builder, clientHttpRequestFactoryBuilderCustomizers.orderedStream().toList());
}
@SuppressWarnings("unchecked")
private ClientHttpRequestFactoryBuilder<?> customize(ClientHttpRequestFactoryBuilder<?> builder,
List<ClientHttpRequestFactoryBuilderCustomizer<?>> customizers) {
ClientHttpRequestFactoryBuilder<?>[] builderReference = { builder };
LambdaSafe.callbacks(ClientHttpRequestFactoryBuilderCustomizer.class, customizers, builderReference[0])
.invoke((customizer) -> builderReference[0] = customizer.customize(builderReference[0]));
.invoke((customizer) -> builderReference[0] = customizer.customize(builderReference[0]));
return builderReference[0];
}

Loading…
Cancel
Save