Skip to content

Commit e32e335

Browse files
smartandhandsomephilwebb
authored andcommitted
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>
1 parent 53ff2de commit e32e335

File tree

2 files changed

+25
-2
lines changed

2 files changed

+25
-2
lines changed

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import java.net.http.HttpClient;
2020
import java.util.Collection;
2121
import java.util.List;
22+
import java.util.concurrent.Executors;
2223
import java.util.function.Consumer;
2324

2425
import org.jspecify.annotations.Nullable;
@@ -75,6 +76,12 @@ public JdkClientHttpRequestFactoryBuilder withHttpClientCustomizer(
7576
this.httpClientBuilder.withCustomizer(httpClientCustomizer));
7677
}
7778

79+
public JdkClientHttpRequestFactoryBuilder enableVirtualThreadExecutor() {
80+
return this.withHttpClientCustomizer(builder ->
81+
builder.executor(Executors.newVirtualThreadPerTaskExecutor())
82+
);
83+
}
84+
7885
@Override
7986
protected JdkClientHttpRequestFactory createClientHttpRequestFactory(ClientHttpRequestFactorySettings settings) {
8087
HttpClient httpClient = this.httpClientBuilder.build(asHttpClientSettings(settings.withReadTimeout(null)));

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

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,13 @@
2424
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
2525
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
2626
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
27+
import org.springframework.boot.autoconfigure.condition.ConditionalOnThreading;
2728
import org.springframework.boot.autoconfigure.ssl.SslAutoConfiguration;
29+
import org.springframework.boot.autoconfigure.thread.Threading;
2830
import org.springframework.boot.context.properties.EnableConfigurationProperties;
2931
import org.springframework.boot.http.client.ClientHttpRequestFactoryBuilder;
3032
import org.springframework.boot.http.client.ClientHttpRequestFactorySettings;
33+
import org.springframework.boot.http.client.JdkClientHttpRequestFactoryBuilder;
3134
import org.springframework.boot.ssl.SslBundles;
3235
import org.springframework.boot.util.LambdaSafe;
3336
import org.springframework.context.annotation.Bean;
@@ -64,18 +67,31 @@ public void setBeanClassLoader(ClassLoader classLoader) {
6467

6568
@Bean
6669
@ConditionalOnMissingBean
67-
ClientHttpRequestFactoryBuilder<?> clientHttpRequestFactoryBuilder(
70+
@ConditionalOnThreading(Threading.PLATFORM)
71+
ClientHttpRequestFactoryBuilder<?> clientHttpRequestFactoryBuilderOnPlatform(
6872
ObjectProvider<ClientHttpRequestFactoryBuilderCustomizer<?>> clientHttpRequestFactoryBuilderCustomizers) {
6973
ClientHttpRequestFactoryBuilder<?> builder = this.factories.builder(this.beanClassLoader);
7074
return customize(builder, clientHttpRequestFactoryBuilderCustomizers.orderedStream().toList());
7175
}
7276

77+
@Bean
78+
@ConditionalOnMissingBean
79+
@ConditionalOnThreading(Threading.VIRTUAL)
80+
ClientHttpRequestFactoryBuilder<?> clientHttpRequestFactoryBuilderOnVirtual(
81+
ObjectProvider<ClientHttpRequestFactoryBuilderCustomizer<?>> clientHttpRequestFactoryBuilderCustomizers) {
82+
ClientHttpRequestFactoryBuilder<?> builder = this.factories.builder(this.beanClassLoader);
83+
if (builder instanceof JdkClientHttpRequestFactoryBuilder jdk) {
84+
return customize(jdk.enableVirtualThreadExecutor(), clientHttpRequestFactoryBuilderCustomizers.orderedStream().toList());
85+
}
86+
return customize(builder, clientHttpRequestFactoryBuilderCustomizers.orderedStream().toList());
87+
}
88+
7389
@SuppressWarnings("unchecked")
7490
private ClientHttpRequestFactoryBuilder<?> customize(ClientHttpRequestFactoryBuilder<?> builder,
7591
List<ClientHttpRequestFactoryBuilderCustomizer<?>> customizers) {
7692
ClientHttpRequestFactoryBuilder<?>[] builderReference = { builder };
7793
LambdaSafe.callbacks(ClientHttpRequestFactoryBuilderCustomizer.class, customizers, builderReference[0])
78-
.invoke((customizer) -> builderReference[0] = customizer.customize(builderReference[0]));
94+
.invoke((customizer) -> builderReference[0] = customizer.customize(builderReference[0]));
7995
return builderReference[0];
8096
}
8197

0 commit comments

Comments
 (0)