背景
在Spring项目中,我们往往使用RestTemplate、HttpClient、OkHttp实现远程服务的调用。
随着Spring 6 和 Spring Boot 3版本的发布,Spring 6.1 M2 版本引入了RestClient客户端,并且在官方文档中强烈建议使用 。
If you are not using Spring WebFlux or Project Reactor in your application we recommend that you use RestClient to call remote REST services.
接下来,我们尝鲜试用一下:
客户端配置
package com.example.demo.config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestClient;
@Configuration
public class RestClientConfig {
@Value("${demo.url}")
private String demoServiceUrl;
@Bean
public RestClient restClient() {
return RestClient.builder().baseUrl(demoServiceUrl).build();
}
}
- 可以按照服务地址创建不同的Client。
基本使用
package com.example.demo.service;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestClient;
@Service
public class RestClientService {
@Resource
private RestClient restClient;
public String sayHello(String hello) {
String res = restClient.get().uri("say1/{content}", hello).retrieve().body(String.class);
return "say:" + res;
}
}
高级配置
通常我们需要设置一些个性话参数来满足我们的需求,可以通设置factory、converters实现灵活使用,详情可以参考API:
/**
* A mutable builder for creating a {@link RestClient}.
*/
interface Builder {
/**
* Configure a base URL for requests. Effectively a shortcut for:
* <pre class="code">
* String baseUrl = "https://abc.go.com/v1";
* DefaultUriBuilderFactory factory = new DefaultUriBuilderFactory(baseUrl);
* RestClient client = RestClient.builder().uriBuilderFactory(factory).build();
* </pre>
* <p>The {@code DefaultUriBuilderFactory} is used to prepare the URL
* for every request with the given base URL, unless the URL request
* for a given URL is absolute in which case the base URL is ignored.
* <p><strong>Note:</strong> this method is mutually exclusive with
* {@link #uriBuilderFactory(UriBuilderFactory)}. If both are used, the
* {@code baseUrl} value provided here will be ignored.
* @return this builder
* @see DefaultUriBuilderFactory#DefaultUriBuilderFactory(String)
* @see #uriBuilderFactory(UriBuilderFactory)
*/
Builder baseUrl(String baseUrl);
/**
* Configure default URL variable values to use when expanding URI
* templates with a {@link Map}. Effectively a shortcut for:
* <pre class="code">
* Map<String, ?> defaultVars = ...;
* DefaultUriBuilderFactory factory = new DefaultUriBuilderFactory();
* factory.setDefaultVariables(defaultVars);
* RestClient client = RestClient.builder().uriBuilderFactory(factory).build();
* </pre>
* <p><strong>Note:</strong> this method is mutually exclusive with
* {@link #uriBuilderFactory(UriBuilderFactory)}. If both are used, the
* {@code defaultUriVariables} value provided here will be ignored.
* @return this builder
* @see DefaultUriBuilderFactory#setDefaultUriVariables(Map)
* @see #uriBuilderFactory(UriBuilderFactory)
*/
Builder defaultUriVariables(Map<String, ?> defaultUriVariables);
/**
* Provide a pre-configured {@link UriBuilderFactory} instance. This is
* an alternative to, and effectively overrides the following shortcut
* properties:
* <ul>
* <li>{@link #baseUrl(String)}
* <li>{@link #defaultUriVariables(Map)}.
* </ul>
* @param uriBuilderFactory the URI builder factory to use
* @return this builder
* @see #baseUrl(String)
* @see #defaultUriVariables(Map)
*/
Builder uriBuilderFactory(UriBuilderFactory uriBuilderFactory);
/**
* Global option to specify a header to be added to every request,
* if the request does not already contain such a header.
* @param header the header name
* @param values the header values
* @return this builder
*/
Builder defaultHeader(String header, String... values);
/**
* Provide a consumer to access to every {@linkplain #defaultHeader(String, String...)
* default header} declared so far, with the possibility to add, replace, or remove.
* @param headersConsumer the consumer
* @return this builder
*/
Builder defaultHeaders(Consumer<HttpHeaders> headersConsumer);
/**
* Provide a consumer to customize every request being built.
* @param defaultRequest the consumer to use for modifying requests
* @return this builder
*/
Builder defaultRequest(Consumer<RequestHeadersSpec<?>> defaultRequest);
/**
* Register a default
* {@linkplain ResponseSpec#onStatus(Predicate, ResponseSpec.ErrorHandler) status handler}
* to apply to every response. Such default handlers are applied in the
* order in which they are registered, and after any others that are
* registered for a specific response.
* @param statusPredicate to match responses with
* @param errorHandler handler that typically, though not necessarily,
* throws an exception
* @return this builder
*/
Builder defaultStatusHandler(Predicate<HttpStatusCode> statusPredicate,
ResponseSpec.ErrorHandler errorHandler);
/**
* Register a default
* {@linkplain ResponseSpec#onStatus(ResponseErrorHandler) status handler}
* to apply to every response. Such default handlers are applied in the
* order in which they are registered, and after any others that are
* registered for a specific response.
* @param errorHandler handler that typically, though not necessarily,
* throws an exception
* @return this builder
*/
Builder defaultStatusHandler(ResponseErrorHandler errorHandler);
/**
* Add the given request interceptor to the end of the interceptor chain.
* @param interceptor the interceptor to be added to the chain
* @return this builder
*/
Builder requestInterceptor(ClientHttpRequestInterceptor interceptor);
/**
* Manipulate the interceptors with the given consumer. The list provided to
* the consumer is "live", so that the consumer can be used to remove
* interceptors, change ordering, etc.
* @param interceptorsConsumer a function that consumes the interceptors list
* @return this builder
*/
Builder requestInterceptors(Consumer<List<ClientHttpRequestInterceptor>> interceptorsConsumer);
/**
* Add the given request initializer to the end of the initializer chain.
* @param initializer the initializer to be added to the chain
* @return this builder
*/
Builder requestInitializer(ClientHttpRequestInitializer initializer);
/**
* Manipulate the initializers with the given consumer. The list provided to
* the consumer is "live", so that the consumer can be used to remove
* initializers, change ordering, etc.
* @param initializersConsumer a function that consumes the initializers list
* @return this builder
*/
Builder requestInitializers(Consumer<List<ClientHttpRequestInitializer>> initializersConsumer);
/**
* Configure the {@link ClientHttpRequestFactory} to use. This is useful
* for plugging in and/or customizing options of the underlying HTTP
* client library (e.g. SSL).
* <p>If no request factory is specified, {@code RestClient} uses
* {@linkplain org.springframework.http.client.HttpComponentsClientHttpRequestFactory Apache Http Client},
* {@linkplain org.springframework.http.client.JettyClientHttpRequestFactory Jetty Http Client}
* if available on the classpath, and defaults to the
* {@linkplain org.springframework.http.client.JdkClientHttpRequestFactory JDK HttpClient}
* if the {@code java.net.http} module is loaded, or to a
* {@linkplain org.springframework.http.client.SimpleClientHttpRequestFactory simple default}
* otherwise.
* @param requestFactory the request factory to use
* @return this builder
*/
Builder requestFactory(ClientHttpRequestFactory requestFactory);
/**
* Configure the message converters for the {@code RestClient} to use.
* @param configurer the configurer to apply
* @return this builder
*/
Builder messageConverters(Consumer<List<HttpMessageConverter<?>>> configurer);
/**
* Configure the {@link io.micrometer.observation.ObservationRegistry} to use
* for recording HTTP client observations.
* @param observationRegistry the observation registry to use
* @return this builder
*/
Builder observationRegistry(ObservationRegistry observationRegistry);
/**
* Apply the given {@code Consumer} to this builder instance.
* <p>This can be useful for applying pre-packaged customizations.
* @param builderConsumer the consumer to apply
* @return this builder
*/
Builder apply(Consumer<Builder> builderConsumer);
/**
* Clone this {@code RestClient.Builder}.
*/
Builder clone();
/**
* Build the {@link RestClient} instance.
*/
RestClient build();
}
Spring 会根据工程依赖,自动选择客户端的引入,按如下优先级顺序引入:
-
Apache HttpClient
-
Jetty HttpClient
-
OkHttp (deprecated)
-
Simple JDK client (HttpURLConnection)