Change 'blocking' term to 'imperative'

Closes gh-47398
This commit is contained in:
Phillip Webb
2025-10-15 13:11:10 -07:00
parent 55e7c83498
commit 94199a63fa
19 changed files with 49 additions and 48 deletions
@@ -3,7 +3,7 @@
Spring Boot provides various convenient ways to call remote REST services.
If you are developing a non-blocking reactive application and you're using Spring WebFlux, then you can use javadoc:org.springframework.web.reactive.function.client.WebClient[].
If you prefer blocking APIs then you can use javadoc:org.springframework.web.client.RestClient[] or javadoc:org.springframework.web.client.RestTemplate[].
If you prefer imperative APIs then you can use javadoc:org.springframework.web.client.RestClient[] or javadoc:org.springframework.web.client.RestTemplate[].
@@ -15,7 +15,7 @@ The javadoc:org.springframework.web.reactive.function.client.WebClient[] interfa
You can learn more about the javadoc:org.springframework.web.reactive.function.client.WebClient[] in the dedicated {url-spring-framework-docs}/web/webflux-webclient.html[section in the Spring Framework docs].
TIP: If you are not writing a reactive Spring WebFlux application you can use the xref:io/rest-client.adoc#io.rest-client.restclient[`RestClient`] instead of a javadoc:org.springframework.web.reactive.function.client.WebClient[].
This provides a similar functional API, but is blocking rather than reactive.
This provides a similar functional API, but is imperative rather than reactive.
Spring Boot creates and pre-configures a prototype javadoc:org.springframework.web.reactive.function.client.WebClient$Builder[] bean for you.
It is strongly advised to inject it in your components and use it to create javadoc:org.springframework.web.reactive.function.client.WebClient[] instances.
@@ -112,7 +112,7 @@ include-code::MyService[]
If you are not using Spring WebFlux or Project Reactor in your application we recommend that you use javadoc:org.springframework.web.client.RestClient[] to call remote REST services.
The javadoc:org.springframework.web.client.RestClient[] interface provides a functional style blocking API.
The javadoc:org.springframework.web.client.RestClient[] interface provides a functional style imperative API.
Spring Boot creates and pre-configures a prototype javadoc:org.springframework.web.client.RestClient$Builder[] bean for you.
It is strongly advised to inject it in your components and use it to create javadoc:org.springframework.web.client.RestClient[] instances.
@@ -235,7 +235,7 @@ If multiple clients are available on the classpath, and not global configuration
[[io.rest-client.clienthttprequestfactory.configuration]]
=== Global HTTP Client Configuration
If the auto-detected HTTP client does not meet your needs, you can use the configprop:spring.http.clients.blocking.factory[] property to pick a specific factory.
If the auto-detected HTTP client does not meet your needs, you can use the configprop:spring.http.clients.imperative.factory[] property to pick a specific factory.
For example, if you have Apache HttpClient on your classpath, but you prefer Jetty's javadoc:org.eclipse.jetty.client.HttpClient[] you can add the following:
[configprops,yaml]
@@ -243,7 +243,7 @@ For example, if you have Apache HttpClient on your classpath, but you prefer Jet
spring:
http:
clients:
blocking:
imperative:
factory: jetty
----
@@ -23,7 +23,7 @@ import org.jspecify.annotations.Nullable;
import org.springframework.boot.ssl.SslBundle;
/**
* Settings that can be applied when creating a blocking or reactive HTTP client.
* Settings that can be applied when creating a imperative or reactive HTTP client.
*
* @param redirects the follow redirect strategy to use or null to redirect whenever the
* underlying library allows it
@@ -22,7 +22,7 @@ import org.springframework.boot.context.properties.ConfigurationPropertiesSource
import org.springframework.boot.context.properties.bind.Name;
/**
* API Version properties for both reactive and blocking HTTP Clients.
* API Version properties for both reactive and imperative HTTP Clients.
*
* @author Phillip Webb
* @since 4.0.0
@@ -26,7 +26,7 @@ import org.springframework.boot.context.properties.ConfigurationPropertiesSource
import org.springframework.boot.context.properties.NestedConfigurationProperty;
/**
* Base class for configuration properties common to both blocking and reactive HTTP
* Base class for configuration properties common to both imperative and reactive HTTP
* clients.
*
* @author Olga Maciaszek-Sharma
@@ -20,7 +20,7 @@ import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* {@link ConfigurationProperties @ConfigurationProperties} to configure the defaults used
* for all blocking and non-blocking HTTP clients.
* for all imperative and reactive HTTP clients.
*
* @author Phillip Webb
* @since 4.0.0
@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.boot.http.client.autoconfigure.blocking;
package org.springframework.boot.http.client.autoconfigure.imperative;
import java.util.List;
@@ -40,7 +40,7 @@ import org.springframework.core.task.VirtualThreadTaskExecutor;
import org.springframework.http.client.ClientHttpRequestFactory;
/**
* {@link EnableAutoConfiguration Auto-configuration} for blocking HTTP clients.
* {@link EnableAutoConfiguration Auto-configuration} for imperative HTTP clients.
*
* @author Phillip Webb
* @author Sangmin Park
@@ -50,19 +50,19 @@ import org.springframework.http.client.ClientHttpRequestFactory;
@AutoConfiguration(after = HttpClientAutoConfiguration.class)
@ConditionalOnClass(ClientHttpRequestFactory.class)
@Conditional(NotReactiveWebApplicationCondition.class)
@EnableConfigurationProperties(BlockingHttpClientsProperties.class)
public final class BlockingHttpClientAutoConfiguration {
@EnableConfigurationProperties(ImperativeHttpClientsProperties.class)
public final class ImperativeHttpClientAutoConfiguration {
private final Environment environment;
BlockingHttpClientAutoConfiguration(Environment environment) {
ImperativeHttpClientAutoConfiguration(Environment environment) {
this.environment = environment;
}
@Bean
@ConditionalOnMissingBean
ClientHttpRequestFactoryBuilder<?> clientHttpRequestFactoryBuilder(ResourceLoader resourceLoader,
BlockingHttpClientsProperties properties,
ImperativeHttpClientsProperties properties,
ObjectProvider<ClientHttpRequestFactoryBuilderCustomizer<?>> clientHttpRequestFactoryBuilderCustomizers) {
ClientHttpRequestFactoryBuilder<?> builder = (properties.getFactory() != null)
? properties.getFactory().builder()
@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.boot.http.client.autoconfigure.blocking;
package org.springframework.boot.http.client.autoconfigure.imperative;
import java.util.function.Supplier;
@@ -26,14 +26,14 @@ import org.springframework.boot.http.client.autoconfigure.HttpClientsProperties;
/**
* {@link ConfigurationProperties @ConfigurationProperties} to configure the defaults used
* for blocking HTTP clients.
* for imperative HTTP clients.
*
* @author Phillip Webb
* @since 4.0.0
* @see HttpClientsProperties
*/
@ConfigurationProperties("spring.http.clients.blocking")
public class BlockingHttpClientsProperties {
@ConfigurationProperties("spring.http.clients.imperative")
public class ImperativeHttpClientsProperties {
/**
* Default factory used for a client HTTP request.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.boot.http.client.autoconfigure.blocking;
package org.springframework.boot.http.client.autoconfigure.imperative;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;
@@ -15,9 +15,9 @@
*/
/**
* Auto-configuration for client-side blocking HTTP.
* Auto-configuration for client-side imperative HTTP.
*/
@NullMarked
package org.springframework.boot.http.client.autoconfigure.blocking;
package org.springframework.boot.http.client.autoconfigure.imperative;
import org.jspecify.annotations.NullMarked;
@@ -16,7 +16,7 @@
"description": "Default factory used for a client HTTP request.",
"deprecated": true,
"deprecation": {
"replacement": "spring.http.clients.blocking.factory",
"replacement": "spring.http.clients.imperative.factory",
"since": "4.0.0"
}
},
@@ -1,4 +1,4 @@
org.springframework.boot.http.client.autoconfigure.HttpClientAutoConfiguration
org.springframework.boot.http.client.autoconfigure.blocking.BlockingHttpClientAutoConfiguration
org.springframework.boot.http.client.autoconfigure.imperative.ImperativeHttpClientAutoConfiguration
org.springframework.boot.http.client.autoconfigure.metrics.HttpClientMetricsAutoConfiguration
org.springframework.boot.http.client.autoconfigure.reactive.ReactiveHttpClientAutoConfiguration
@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.boot.http.client.autoconfigure.blocking;
package org.springframework.boot.http.client.autoconfigure.imperative;
import java.net.http.HttpClient;
import java.time.Duration;
@@ -50,14 +50,14 @@ import org.springframework.test.util.ReflectionTestUtils;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link BlockingHttpClientAutoConfiguration}.
* Tests for {@link ImperativeHttpClientAutoConfiguration}.
*
* @author Phillip Webb
*/
class BlockingHttpClientAutoConfigurationTests {
class ImperativeHttpClientAutoConfigurationTests {
private static final AutoConfigurations autoConfigurations = AutoConfigurations
.of(BlockingHttpClientAutoConfiguration.class, HttpClientAutoConfiguration.class, SslAutoConfiguration.class);
.of(ImperativeHttpClientAutoConfiguration.class, HttpClientAutoConfiguration.class, SslAutoConfiguration.class);
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
.withConfiguration(autoConfigurations);
@@ -69,7 +69,7 @@ class BlockingHttpClientAutoConfigurationTests {
@Test
void configuresDefinedClientHttpRequestFactoryBuilder() {
this.contextRunner.withPropertyValues("spring.http.clients.blocking.factory=simple")
this.contextRunner.withPropertyValues("spring.http.clients.imperative.factory=simple")
.run((context) -> assertThat(context.getBean(ClientHttpRequestFactoryBuilder.class))
.isInstanceOf(SimpleClientHttpRequestFactoryBuilder.class));
}
@@ -146,7 +146,7 @@ class BlockingHttpClientAutoConfigurationTests {
@EnabledForJreRange(min = JRE.JAVA_21)
void whenVirtualThreadsEnabledAndUsingJdkHttpClientUsesVirtualThreadExecutor() {
this.contextRunner
.withPropertyValues("spring.http.clients.blocking.factory=jdk", "spring.threads.virtual.enabled=true")
.withPropertyValues("spring.http.clients.imperative.factory=jdk", "spring.threads.virtual.enabled=true")
.run((context) -> {
ClientHttpRequestFactory factory = context.getBean(ClientHttpRequestFactoryBuilder.class).build();
HttpClient httpClient = (HttpClient) ReflectionTestUtils.getField(factory, "httpClient");
@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.boot.http.client.autoconfigure.blocking;
package org.springframework.boot.http.client.autoconfigure.imperative;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
@@ -24,16 +24,16 @@ import org.springframework.boot.http.client.JdkClientHttpRequestFactoryBuilder;
import org.springframework.boot.http.client.JettyClientHttpRequestFactoryBuilder;
import org.springframework.boot.http.client.ReactorClientHttpRequestFactoryBuilder;
import org.springframework.boot.http.client.SimpleClientHttpRequestFactoryBuilder;
import org.springframework.boot.http.client.autoconfigure.blocking.BlockingHttpClientsProperties.Factory;
import org.springframework.boot.http.client.autoconfigure.imperative.ImperativeHttpClientsProperties.Factory;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link BlockingHttpClientsProperties}.
* Tests for {@link ImperativeHttpClientsProperties}.
*
* @author Phillip Webb
*/
class BlockingHttpClientsPropertiesTests {
class ImperativeHttpClientsPropertiesTests {
@Nested
class FactoryTests {
@@ -27,7 +27,7 @@ import org.springframework.boot.autoconfigure.ssl.SslAutoConfiguration;
import org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguration;
import org.springframework.boot.http.client.ClientHttpRequestFactoryBuilder;
import org.springframework.boot.http.client.HttpClientSettings;
import org.springframework.boot.http.client.autoconfigure.blocking.BlockingHttpClientAutoConfiguration;
import org.springframework.boot.http.client.autoconfigure.imperative.ImperativeHttpClientAutoConfiguration;
import org.springframework.boot.http.converter.autoconfigure.ClientHttpMessageConvertersCustomizer;
import org.springframework.boot.restclient.RestClientCustomizer;
import org.springframework.boot.ssl.SslBundles;
@@ -54,7 +54,7 @@ import org.springframework.web.client.RestClient.Builder;
* @author Phillip Webb
* @since 4.0.0
*/
@AutoConfiguration(after = { BlockingHttpClientAutoConfiguration.class, TaskExecutionAutoConfiguration.class,
@AutoConfiguration(after = { ImperativeHttpClientAutoConfiguration.class, TaskExecutionAutoConfiguration.class,
SslAutoConfiguration.class })
@ConditionalOnClass(RestClient.class)
@Conditional(NotReactiveWebApplicationOrVirtualThreadsExecutorEnabledCondition.class)
@@ -23,7 +23,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.http.client.ClientHttpRequestFactoryBuilder;
import org.springframework.boot.http.client.HttpClientSettings;
import org.springframework.boot.http.client.autoconfigure.blocking.BlockingHttpClientAutoConfiguration;
import org.springframework.boot.http.client.autoconfigure.imperative.ImperativeHttpClientAutoConfiguration;
import org.springframework.boot.http.client.autoconfigure.service.HttpServiceClientProperties;
import org.springframework.boot.restclient.RestClientCustomizer;
import org.springframework.boot.restclient.autoconfigure.RestClientAutoConfiguration;
@@ -43,7 +43,7 @@ import org.springframework.web.service.registry.HttpServiceProxyRegistry;
* @author Phillip Webb
* @since 4.0.0
*/
@AutoConfiguration(after = { BlockingHttpClientAutoConfiguration.class, RestClientAutoConfiguration.class })
@AutoConfiguration(after = { ImperativeHttpClientAutoConfiguration.class, RestClientAutoConfiguration.class })
@ConditionalOnClass(RestClientAdapter.class)
@ConditionalOnBean(HttpServiceProxyRegistry.class)
@Conditional(NotReactiveWebApplicationCondition.class)
@@ -29,7 +29,7 @@ import org.springframework.boot.http.client.ClientHttpRequestFactoryBuilder;
import org.springframework.boot.http.client.HttpClientSettings;
import org.springframework.boot.http.client.HttpRedirects;
import org.springframework.boot.http.client.autoconfigure.HttpClientAutoConfiguration;
import org.springframework.boot.http.client.autoconfigure.blocking.BlockingHttpClientAutoConfiguration;
import org.springframework.boot.http.client.autoconfigure.imperative.ImperativeHttpClientAutoConfiguration;
import org.springframework.boot.http.client.autoconfigure.reactive.ReactiveHttpClientAutoConfiguration;
import org.springframework.boot.http.converter.autoconfigure.HttpMessageConvertersAutoConfiguration;
import org.springframework.boot.restclient.RestClientCustomizer;
@@ -64,7 +64,7 @@ class RestClientAutoConfigurationTests {
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(RestClientAutoConfiguration.class, HttpClientAutoConfiguration.class,
BlockingHttpClientAutoConfiguration.class, ReactiveHttpClientAutoConfiguration.class));
ImperativeHttpClientAutoConfiguration.class, ReactiveHttpClientAutoConfiguration.class));
@Test
void shouldSupplyBeans() {
@@ -191,7 +191,7 @@ class RestClientAutoConfigurationTests {
void whenHasFactoryProperty() {
this.contextRunner.withConfiguration(AutoConfigurations.of(HttpMessageConvertersAutoConfiguration.class))
.withUserConfiguration(RestClientConfig.class)
.withPropertyValues("spring.http.clients.blocking.factory=simple")
.withPropertyValues("spring.http.clients.imperative.factory=simple")
.run((context) -> {
assertThat(context).hasSingleBean(RestClient.class);
RestClient restClient = context.getBean(RestClient.class);
@@ -23,7 +23,7 @@ import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.support.BeanDefinitionOverrideException;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.http.client.autoconfigure.HttpClientAutoConfiguration;
import org.springframework.boot.http.client.autoconfigure.blocking.BlockingHttpClientAutoConfiguration;
import org.springframework.boot.http.client.autoconfigure.imperative.ImperativeHttpClientAutoConfiguration;
import org.springframework.boot.http.converter.autoconfigure.HttpMessageConvertersAutoConfiguration;
import org.springframework.boot.restclient.RestTemplateBuilder;
import org.springframework.boot.restclient.RestTemplateCustomizer;
@@ -59,7 +59,7 @@ class RestTemplateAutoConfigurationTests {
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(RestTemplateAutoConfiguration.class, HttpClientAutoConfiguration.class,
BlockingHttpClientAutoConfiguration.class));
ImperativeHttpClientAutoConfiguration.class));
@Test
void restTemplateBuilderConfigurerShouldBeLazilyDefined() {
@@ -184,7 +184,7 @@ class RestTemplateAutoConfigurationTests {
void whenHasFactoryProperty() {
this.contextRunner.withConfiguration(AutoConfigurations.of(HttpMessageConvertersAutoConfiguration.class))
.withUserConfiguration(RestTemplateConfig.class)
.withPropertyValues("spring.http.clients.blocking.factory=simple")
.withPropertyValues("spring.http.clients.imperative.factory=simple")
.run((context) -> {
assertThat(context).hasSingleBean(RestTemplate.class);
RestTemplate restTemplate = context.getBean(RestTemplate.class);
@@ -33,7 +33,7 @@ import org.springframework.boot.http.client.ClientHttpRequestFactoryBuilder;
import org.springframework.boot.http.client.HttpClientSettings;
import org.springframework.boot.http.client.HttpRedirects;
import org.springframework.boot.http.client.autoconfigure.HttpClientAutoConfiguration;
import org.springframework.boot.http.client.autoconfigure.blocking.BlockingHttpClientAutoConfiguration;
import org.springframework.boot.http.client.autoconfigure.imperative.ImperativeHttpClientAutoConfiguration;
import org.springframework.boot.restclient.RestClientCustomizer;
import org.springframework.boot.restclient.autoconfigure.RestClientAutoConfiguration;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
@@ -70,7 +70,7 @@ class HttpServiceClientAutoConfigurationTests {
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(HttpServiceClientAutoConfiguration.class,
BlockingHttpClientAutoConfiguration.class, RestClientAutoConfiguration.class));
ImperativeHttpClientAutoConfiguration.class, RestClientAutoConfiguration.class));
@Test
void configuresClientFromProperties() {
@@ -146,7 +146,7 @@ class HttpServiceClientAutoConfigurationTests {
void whenHasUserDefinedRequestFactorySettings() {
this.contextRunner
.withPropertyValues("spring.http.serviceclient.one.base-url=https://example.com",
"spring.http.clients.blocking.factory=jdk")
"spring.http.clients.imperative.factory=jdk")
.withUserConfiguration(HttpClientConfiguration.class, RequestFactorySettingsConfiguration.class)
.run((context) -> {
TestClientOne clientOne = context.getBean(TestClientOne.class);
@@ -44,7 +44,8 @@ import static org.assertj.core.api.Assertions.assertThat;
* @author Dave Syer
* @author Scott Frederick
*/
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, properties = "spring.http.clients.blocking.factory=simple")
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT,
properties = "spring.http.clients.imperative.factory=simple")
@AutoConfigureTestRestTemplate
class SampleMethodSecurityApplicationTests {