作为 Java 后端开发者,你对 RestClient 的关注,反映了你对现代、简洁、类型安全 HTTP 客户端的追求。Spring 6.1 引入的 RestClient 不是 RestTemplate 的简单升级,而是Spring 官方为同步世界设计的下一代 HTTP 客户端,它融合了现代 Java 的函数式风格、类型安全与极简 API,是 RestTemplate 的正式继任者。
以下是一份最标准、最实战、带完整中文注释的 RestClient 详解文档,涵盖其定义、作用、特点、与 RestTemplate 的对比、生产级配置、最佳实践与真实业务示例。
📄 RestClient:Spring 6.1+ 同步 HTTP 客户端权威说明文档
版本:2025年10月
适用对象:Java 后端开发者 / 传统 Spring MVC 架构师
目标:彻底掌握 RestClient 的设计理念、核心能力、配置规范与生产级使用方式
一、RestClient 是什么?
✅ 官方定义(Spring Framework 6.1+)
RestClient 是 Spring 6.1 引入的现代、流畅(fluent)、同步、类型安全的 HTTP 客户端,用于替代已弃用的
RestTemplate。它基于HttpComponents Client(Apache HttpClient 5)构建,提供链式 API、自动编解码、响应体直接映射、异常统一处理,专为同步阻塞式应用(如 Spring MVC、传统微服务)设计。
🔑 核心定位
- 不是“异步”客户端:它是为阻塞式编程模型(Spring MVC、定时任务、批处理)量身打造的。
- 不是“WebClient 的同步版”:它是独立设计的全新 API,与 WebClient 无继承关系。
- 完全替代 RestTemplate:官方明确声明
RestTemplate已@Deprecated,RestClient 是唯一推荐的新方案。 - 与 Spring MVC 同构:使用相同的
HttpMessageConverter(如 Jackson、Gson),确保请求/响应序列化一致性。
💡 一句话理解:
RestClient = RestTemplate 的现代化重构版 —— 更简洁、更安全、更易测试、更少样板代码。
二、RestClient 有什么作用?
| 作用 | 说明 |
|---|---|
| ✅ 调用外部 REST API | 如:调用支付网关、短信服务、第三方用户中心 |
| ✅ 微服务间同步通信 | 服务 A 同步调用服务 B,等待结果后继续流程 |
| ✅ 批处理任务中调用 HTTP | 如:每天凌晨同步用户数据、导出报表 |
| ✅ 定时任务调用外部服务 | 如:每小时拉取汇率、刷新缓存 |
| ✅ 与 Spring MVC 无缝集成 | 无需引入响应式依赖,直接在 @RestController 中使用 |
| ✅ 自动对象映射 | Java 对象 ↔ JSON/XML 自动序列化/反序列化 |
| ✅ 统一异常处理 | 所有 HTTP 错误(4xx/5xx)自动抛出 RestClientException |
✅ 典型场景:
你正在写一个 Spring Boot 3.2 + Spring MVC 的订单系统,需要在用户下单时同步调用风控服务 —— RestClient 就是你的最佳选择。
三、RestClient 的核心特点(与 RestTemplate 对比)
| 特性 | RestClient | RestTemplate |
|---|---|---|
| API 设计 | ✅ 现代 Fluent 链式 API ( restClient.get().uri(...).retrieve().toEntity(...)) | ❌ 传统方法调用 ( getForObject(url, class, args)) |
| 类型安全 | ✅ 编译期检查 URI 参数、请求体、响应类型 | ❌ 运行时校验,易出错 |
| 是否弃用 | ✅ ✅ ✅ 官方推荐的新标准 | ❌ 已标记为 @Deprecated |
| 底层实现 | ✅ Apache HttpClient 5(高性能、连接池) | ❌ Apache HttpClient 4(老旧) |
| 异常体系 | ✅ 统一 RestClientException 及子类(ResponseException、RequestException) | ❌ 多种异常(HttpClientException、RestClientException) |
| 编解码一致性 | ✅ 与 @RestController 使用相同 HttpMessageConverter(Jackson/Gson) | ✅ 也支持,但配置分散 |
| 是否支持异步 | ❌ 否(同步阻塞) | ❌ 否 |
| 是否支持流式 | ❌ 否 | ❌ 否 |
| 是否支持 HTTP/2 | ✅ 是(HttpClient 5 支持) | ✅ 有限支持 |
| 是否支持拦截器 | ✅ ClientHttpRequestInterceptor | ✅ 支持 |
| 是否支持重试/熔断 | ❌ 无内置 | ❌ 无内置(需集成 Resilience4j) |
| 是否推荐用于新项目 | ✅✅✅ 官方唯一推荐 | ❌ 禁止用于新项目 |
| 学习成本 | 低(API 简洁直观) | 中(方法繁多,参数易混淆) |
🚫 Spring 官方声明:
“RestTemplate 已被弃用,所有新项目应使用 RestClient。”
—— Spring Framework 6.1+ 文档
四、为什么必须使用 RestClient?(不使用会怎样?)
❌ 错误做法:继续使用 RestTemplate(已弃用)
@RestController
public class OrderController {
@Autowired
private RestTemplate restTemplate; // ⚠️ 已弃用!未来版本将移除
@PostMapping("/orders")
public Order createOrder(@RequestBody OrderRequest request) {
// ❌ 方法名复杂,参数顺序易错,无编译检查
ResponseEntity<Order> response = restTemplate.postForEntity(
"http://risk-service/api/check",
request,
Order.class
);
return response.getBody();
}
}
问题:
- 方法名冗长:
postForEntity,getForObject,exchange等 10+ 种方法。- 参数顺序易错:
url, request, responseType, uriVariables混乱。- 无类型安全:传错参数类型,编译不报错,运行时崩溃。
- 官方明确弃用,未来 Spring 版本将删除,项目将无法升级。
✅ 正确做法:使用 RestClient
@RestController
public class OrderController {
@Autowired
private RestClient restClient; // ✅ 新标准
@PostMapping("/orders")
public Order createOrder(@RequestBody OrderRequest request) {
// ✅ 简洁、流畅、类型安全、编译期检查
return restClient
.post() // 1. 指定 HTTP 方法
.uri("/api/check") // 2. 设置 URI(支持路径变量)
.body(request) // 3. 设置请求体(自动序列化为 JSON)
.retrieve() // 4. 发起请求,准备接收响应
.body(Order.class); // 5. 直接反序列化为 Order 对象,自动处理 4xx/5xx
}
}
✅ 优势:
- 一行代码完成请求 + 响应 + 异常处理。
- 所有参数类型在编译期校验。
- 无需手动处理
ResponseEntity,直接返回业务对象。- 官方支持,未来十年安全可用。
五、RestClient 的标准配置(生产级最佳实践)
✅ 配置要点:
- 复用 RestClient 实例(线程安全,单例)
- 统一配置编码器、超时、重试、日志
- 使用
HttpMessageConverters与服务端一致 - 使用
ClientHttpRequestInterceptor添加全局 Header(如认证)
✅ 配置类示例(Spring Boot 3.2+)
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestClient;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
import org.apache.hc.client5.http.impl.classic.HttpClientBuilder;
import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager;
import org.apache.hc.client5.http.config.RequestConfig;
import org.apache.hc.core5.http.io.SocketConfig;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.time.Duration;
@Configuration
public class RestClientConfig {
private static final Logger log = LoggerFactory.getLogger(RestClientConfig.class);
/**
* 创建全局共享的 RestClient 实例(单例)
* 配置:连接池、超时、编码器、拦截器
*/
@Bean
public RestClient restClient(Jackson2ObjectMapperBuilder jacksonBuilder) {
// 1. 配置底层 HttpClient(Apache HttpClient 5)
CloseableHttpClient httpClient = HttpClientBuilder.create()
.setConnectionManager(new PoolingHttpClientConnectionManager()) // 连接池
.setDefaultSocketConfig(SocketConfig.custom()
.setSoTimeout(5000) // 读超时 5s
.build())
.setDefaultRequestConfig(RequestConfig.custom()
.setConnectTimeout(3000) // 连接超时 3s
.setSocketTimeout(5000) // 读超时 5s
.build())
.build();
// 2. 配置消息转换器:必须与 @RestController 使用相同的 ObjectMapper
// 👉 重要!避免 LocalDate、BigDecimal、枚举等类型反序列化失败
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
converter.setObjectMapper(jacksonBuilder.build()); // ✅ 使用全局 ObjectMapper
// 3. 创建 RestClient,注入 HTTP 客户端和转换器
return RestClient.builder()
.clientHttpConnector(new SpringClientHttpConnector(httpClient)) // 使用 Apache HttpClient 5
.messageConverters(converter) // 使用统一编码器
.defaultHeader("User-Agent", "MyApp/1.0") // ✅ 全局 Header
.build();
}
/**
* 创建专门用于调用支付服务的 RestClient(独立配置)
*/
@Bean
public RestClient paymentRestClient(Jackson2ObjectMapperBuilder jacksonBuilder) {
CloseableHttpClient httpClient = HttpClientBuilder.create()
.setConnectionManager(new PoolingHttpClientConnectionManager())
.setDefaultSocketConfig(SocketConfig.custom()
.setSoTimeout(8000) // 支付服务要求更长超时
.build())
.setDefaultRequestConfig(RequestConfig.custom()
.setConnectTimeout(5000)
.setSocketTimeout(8000)
.build())
.build();
// 添加认证拦截器:所有请求自动携带 API Key
RestClient restClient = RestClient.builder()
.clientHttpConnector(new SpringClientHttpConnector(httpClient))
.messageConverters(new MappingJackson2HttpMessageConverter(jacksonBuilder.build()))
.defaultHeader("Authorization", "Bearer your-payment-api-key") // ✅ 自动添加认证头
.build();
return restClient;
}
}
✅ 关键配置说明:
SpringClientHttpConnector:Spring 提供的适配器,桥接 Apache HttpClient 5 和 RestClient。jacksonBuilder.build():必须使用 Spring Boot 自动配置的 ObjectMapper,否则@JsonFormat、@JsonSerialize注解失效。defaultHeader():全局添加 Header(如认证、追踪 ID)。- 不要手动创建
ObjectMapper,使用Jackson2ObjectMapperBuilder。
六、RestClient 最标准、最实用的使用示例(带详细中文注释)
✅ 示例 1:GET 请求 —— 查询用户信息(基础调用)
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.beans.factory.annotation.Autowired;
@RestController
public class UserController {
@Autowired
private RestClient restClient; // 注入全局 RestClient
/**
* 根据用户 ID 查询用户信息
* 使用 RestClient 发起 GET 请求,直接返回 User 对象
* 如果响应为 404,抛出 RestClientResponseException;5xx 抛出 RestClientException
*/
@GetMapping("/users/{id}")
public User getUser(@PathVariable Long id) {
return restClient
.get() // 1. 发起 GET 请求
.uri("/api/users/{id}", id) // 2. 设置 URI,路径变量自动替换(类型安全!)
.retrieve() // 3. 准备接收响应
.body(User.class); // 4. 直接反序列化为 User 对象,无需处理 ResponseEntity
// ✅ 自动处理 200 OK → 返回对象
// ✅ 自动处理 404 → 抛出 RestClientResponseException
// ✅ 自动处理 500 → 抛出 RestClientException
}
}
✅ 优势:
- 无需写
ResponseEntity<User>。- 无需手动
getBody()。- 无需
try-catch处理异常(可统一拦截)。
✅ 示例 2:POST 请求 —— 创建订单并调用风控服务(链式调用)
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.beans.factory.annotation.Autowired;
@RestController
public class OrderController {
@Autowired
private RestClient restClient;
/**
* 创建订单前调用风控服务进行校验
* 语义:同步阻塞等待风控结果,通过则创建订单,失败则抛异常
*/
@PostMapping("/orders")
public Order createOrder(@RequestBody OrderRequest request) {
// 1. 调用风控服务(同步阻塞)
RiskCheckResult riskResult = restClient
.post() // 1. POST 方法
.uri("/api/risk/check") // 2. URI
.body(request) // 3. 请求体自动序列化为 JSON
.retrieve() // 4. 发起请求
.body(RiskCheckResult.class); // 5. 反序列化为响应对象
// 2. 如果风控拒绝,抛出业务异常
if (!riskResult.isAllowed()) {
throw new BusinessException("风控未通过:" + riskResult.getReason());
}
// 3. 风控通过,继续创建订单(此处省略本地创建逻辑)
return new Order(request.getUserId(), request.getAmount(), "CREATED");
}
// 👇 辅助类(仅用于示例)
record OrderRequest(Long userId, Double amount) {}
record RiskCheckResult(Boolean isAllowed, String reason) {}
record Order(Long userId, Double amount, String status) {}
}
✅ 关键点:
body(request):自动调用ObjectMapper序列化为 JSON。.body(RiskCheckResult.class):自动反序列化,类型安全,编译期检查。- 代码像普通同步方法一样简单,但底层是高性能 Apache HttpClient 5。
✅ 示例 3:带路径变量和查询参数的复杂请求
@GetMapping("/products")
public Product getProduct(@RequestParam String category,
@RequestParam(required = false) Integer minPrice,
@RequestParam(required = false) Integer maxPrice) {
return restClient
.get() // GET 请求
.uri("/api/products/{category}", category) // 路径变量
.queryParam("minPrice", minPrice) // 查询参数(自动处理 null)
.queryParam("maxPrice", maxPrice) // 查询参数(自动处理 null)
.retrieve()
.body(Product.class);
}
✅ 优势:
queryParam(key, value):自动跳过 null 值,避免?minPrice=null。- 所有参数类型安全,编译期检查。
✅ 示例 4:使用拦截器统一添加追踪 ID(生产级日志)
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.http.HttpRequest;
import org.springframework.http.client.ClientHttpRequestExecution;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.io.IOException;
@Component
public class TraceIdInterceptor implements ClientHttpRequestInterceptor {
@Override
public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
// ✅ 为每个请求自动添加追踪 ID(如 X-Trace-ID)
request.getHeaders().add("X-Trace-ID", TraceContext.getTraceId()); // 假设你有 TraceContext 工具类
return execution.execute(request, body);
}
}
// 在配置类中注册拦截器
@Bean
public RestClient restClient(Jackson2ObjectMapperBuilder jacksonBuilder, TraceIdInterceptor traceIdInterceptor) {
return RestClient.builder()
.clientHttpConnector(new SpringClientHttpConnector(httpClient))
.messageConverters(new MappingJackson2HttpMessageConverter(jacksonBuilder.build()))
.interceptors(traceIdInterceptor) // ✅ 注册拦截器
.build();
}
✅ 作用:
- 所有 HTTP 请求自动携带
X-Trace-ID,便于链路追踪(配合 Sleuth/Zipkin)。- 无需在每个调用处手动添加 Header。
✅ 示例 5:统一异常处理(全局兜底)
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestClientResponseException;
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(RestClientResponseException.class)
public ResponseEntity<ErrorResponse> handleRestClientError(RestClientResponseException e) {
log.error("外部服务调用失败,状态码:{},响应体:{}", e.getStatusCode(), e.getResponseBodyAsString(), e);
ErrorResponse error = new ErrorResponse(
"EXTERNAL_SERVICE_ERROR",
"调用外部服务失败:" + e.getMessage(),
e.getStatusCode().value()
);
return ResponseEntity.status(e.getStatusCode()).body(error);
}
@ExceptionHandler(RestClientException.class)
public ResponseEntity<ErrorResponse> handleGeneralError(RestClientException e) {
log.error("HTTP 客户端错误", e);
ErrorResponse error = new ErrorResponse(
"CLIENT_ERROR",
"网络或客户端错误:" + e.getMessage(),
500
);
return ResponseEntity.status(500).body(error);
}
}
// 👇 数据模型
record ErrorResponse(String code, String message, int status) {}
✅ 作用:
- 所有
RestClient抛出的异常统一被拦截,返回标准错误格式。- 无需在每个 Controller 中写 try-catch。
七、RestClient 使用最佳实践(生产环境清单)
| 类别 | 推荐做法 | 说明 |
|---|---|---|
| ✅ 实例管理 | 单例共享 RestClient | 不要每次调用 RestClient.create(),浪费资源 |
| ✅ 超时配置 | 明确设置 socketTimeout 和 connectTimeout | 避免服务雪崩,建议 3~8s |
| ✅ 编码器 | 使用 Jackson2ObjectMapperBuilder.build() 构建 ObjectMapper | 保证与 @RestController 一致,避免日期/枚举反序列化失败 |
| ✅ 日志监控 | 使用 @RestControllerAdvice 统一处理 RestClientResponseException | 避免 500 泛滥,返回结构化错误 |
| ✅ 重试机制 | 集成 Resilience4j 或 Spring Retry | RestClient 无内置重试,需手动添加 @Retryable |
| ✅ 认证 | 使用 interceptors() 添加全局 Header(如 Authorization) | 避免重复代码 |
| ✅ 测试 | 使用 MockRestServiceServer(Spring Test)模拟 HTTP 响应 | 无需启动真实服务即可测试 |
| ❌ 绝对禁止 | 继续使用 RestTemplate | 官方已弃用,未来版本将移除 |
| ❌ 绝对禁止 | 在 RestClient 中使用 .block() | RestClient 本身就是同步阻塞,无需 block |
| ❌ 绝对禁止 | 手动创建 ObjectMapper | 使用 Spring Boot 自动配置的版本 |
八、RestClient 与 RestTemplate 对比总结表(决策指南)
| 项目 | RestClient | RestTemplate |
|---|---|---|
| 是否推荐用于新项目 | ✅✅✅ 必选 | ❌ 禁止 |
| 是否已弃用 | ❌(官方推荐) | ✅(@Deprecated) |
| API 风格 | ✅ 现代 Fluent 链式 | ❌ 传统方法名繁多 |
| 类型安全 | ✅ 编译期检查 | ❌ 运行时校验 |
| 底层库 | ✅ Apache HttpClient 5 | ❌ Apache HttpClient 4 |
| 异常体系 | ✅ 统一 RestClientException | ❌ 多种异常 |
| 是否支持 Spring Boot 3.x | ✅✅✅ 完全支持 | ✅ 支持,但不推荐 |
| 是否支持 HTTP/2 | ✅ 是 | ✅ 有限支持 |
| 是否支持拦截器 | ✅ 是 | ✅ 是 |
| 是否支持重试 | ❌ 无内置 | ❌ 无内置 |
| 是否适合 Spring MVC | ✅✅✅ 首选 | ⚠️ 已淘汰 |
| 是否适合微服务 | ✅✅✅ 首选 | ❌ 不推荐 |
| 学习成本 | 极低 | 中等 |
🚀 结论:
RestClient 是 Spring 生态中同步 HTTP 客户端的未来。
任何新项目,无论是否使用 WebFlux,只要你是同步阻塞架构,都应优先选择 RestClient。
✅ 附录:RestClient 常用操作速查表
| 操作 | 方法 | 说明 |
|---|---|---|
| GET | .get() | 发起 GET 请求 |
| POST | .post() | 发起 POST 请求 |
| PUT | .put() | 发起 PUT 请求 |
| DELETE | .delete() | 发起 DELETE 请求 |
| 设置 URI | .uri("/path/{id}", id) | 支持路径变量,自动转义 |
| 设置查询参数 | .queryParam("key", value) | 自动跳过 null 值 |
| 设置请求体 | .body(obj) | 自动序列化为 JSON |
| 设置 Header | .header("key", "value") | 单个头 |
| 设置多个 Header | .headers(h -> h.addAll(...)) | 批量设置 |
| 发起请求 | .retrieve() | 准备接收响应 |
| 获取响应体 | .body(Class<T>) | 直接反序列化为对象 |
| 获取完整响应 | .toEntity(Class<T>) | 返回 ResponseEntity<T>(含状态码、头) |
| 添加拦截器 | .interceptors(interceptor) | 全局拦截请求/响应 |
| 设置超时 | 通过 HttpClientBuilder 配置 | RestClient 不直接暴露超时,需配置底层 HttpClient |
📌 结语:RestClient 不是“新瓶装旧酒”,而是“现代化的必然”
RestTemplate 是“你用电话簿打电话”——号码多、记不住、容易打错。
RestClient 是“你用微信发消息”——输入自动补全,发送后自动知道对方是否收到。
当你使用 RestClient,你不是在“写 HTTP 请求”,
你是在声明一个类型安全、语义清晰的业务操作:
“请把这份订单发给风控服务,如果它说‘拒绝’,我就抛异常;如果它说‘通过’,我就继续。”
这才是现代 Java 后端开发应有的优雅与自信。
✅ 行动建议:
- 立即替换所有
RestTemplate实例为RestClient- 统一配置
Jackson2ObjectMapperBuilder与HttpMessageConverter- 为每个外部服务创建独立的 RestClient Bean
- 为所有请求添加
Trace-ID拦截器- 为所有异常编写统一的
@RestControllerAdvice

1389





