The worst《spring RestTemplate》in history
Spring RestTemplate 概述、核心特性、模板方法、底层实现、核心组件类图、核心组件简述、常用 HTTP 方法使用示例、与 WebClient 区别。
版本
- jdk:17
- spring:6.1.3
- spring boot:3.2.2
目录
1 概述
RestTemplate 是 spring framework 框架提供的一个同步的 HTTP 客户端工具类,属于 spring web 模块的一部分。它简化了与 HTTP 服务器的交互,为 RESTful 风格服务调用提供了模板化的方法。
1.1 核心特性
- 模板化设计:提供常见 HTTP 操作(如 GET、POST 等)的快捷方法。
- 同步请求:所有方法都是阻塞式的,会等待服务器响应。
- 消息转换:会自动处理请求和响应的序列化与反序列化。
- 线程安全:RestTemplate 实例是线程安全的,可在多个线程之间共享。
- 异常转换:会将 HTTP 错误转换为 spring 的异常体系。
- 灵活配置:支持多种底层 HTTP 客户端实现。
1.2 模版方法
RestTemplate 为每种 HTTP 方法提供了多种便捷使用方法:
- GET:getForObject()、getForEntity()
- POST:postForObject()、postForEntity()、postForLocation()
- PUT:put()
- DELETE:delete()
- PATCH:patchForObject()
- HEAD:headForHeaders()
- OPTIONS:optionsForAllow()
- 通用方法:exchange()、execute()
1.3 底层实现
RestTemplate 底层依赖于其他 HTTP 客户端实现,提供了 ClientHttpRequestFactory 接口作为其它组件与 spring web 集成的规范。常见的底层 HTTP 客户端实现有:
- JDK 标准 HttpURLConnection(若为引入其它实现,则默认使用该实现)。
- Apache HttpClient
- OkHttp
- Netty
- Jetty
- 其它实现了 ClientHttpRequestFactory 接口的客户端。
2 核心组件
2.1 核心组件类图

2.2 核心组件简述
RestTemplate 相关类组件简要说要及相关关系如下:
-
RestOperations:该接口规定了 RESTful 操作的基础集合,由 RestTemplate 实现此接口,通常不直接使用。
如 getForObject()、getForEntity()、postForObject()、postForObject()、exchange()、execute() 方法等。
-
RestTemplate:实现了 RestOperations 接口,具体实现了 RESTful 接口调用的各类方法。
- 该类通过聚合 ClientHttpRequestFactory 类来实现请求对象的创建及调用。
- 该类通过聚合 ResponseExtractor 类来实现响应结果的获取。
- 该类通过聚合 HttpMessageConverter 类来协助 ResponseExtractor 对响应结果进行消息转换。
- 该类通过聚合 ResponseErrorHeandler 来将 HTTP 错误转换为 spring 异常(IOException)。
-
ClientHttpRequestFactory:HTTP 客户端工厂接口。其声明了 createRequest() 方法,该方法用来创建 ClientHttpRequest 实例。若要在 spring web 中集成其它第三方 HTTP 客户端或自定义实现 HTTP 客户端则需实现该接口。同时,spring web 为我们提供了主流 HTTP 客户端库的实现:
- SimpleClientHttpRequestFactory:针对 JDK(HttpURLConnection)标准库的实现。注:默认使用该实现。
- HttpComponentsClientHttpRequestFactory:针对 Apache 库的实现。
- OkHttp3ClientHttpRequestFactory:针对 OkHttp 库的实现。注:该实现在 spring 6.1 版中已弃用,在 6.2 版本中将移除。
- Netty4ClientHttpRequestFactory:针对 Netty4 库的实现。注:该实现在 spring 5.0 中已弃用,推荐使用响应式客户端 ReactorClientHttpConnector 代替。
- JettyClientHttpRequestFactory:针对 Jetty 库的实现。
-
ClientHttpRequest:http 客户端请求体。该接口声明了 execute() 方法,用来执行 http 请求,并返回响应结果 ClientHttpResponse 对象,同时抛出 IOException 异常。
- 其实例由 ClientHttpRequestFactory 工厂创建。
- 与 ClientHttpRequestFactory 相同,针对不同 HTTP 客户端库有不同的实现,默认使用 SimpleClientHttpRequest 实现。
-
ClientHttpResponse:http 客户端响应体。表示 http 请求的响应结果,包括 HTTP 状态码、响应消息等。
-
ResponseExtractor:响应提取器,声明了 extractData() 方法,负责从 ClientHttpResponse 中提取中真正的响应数据(即业务数据)。
- 该类通过聚合 HttpMessageConverter 类来将 ClientHttpResponse 中的响应流数据转换为目标格式。
-
ResponseErrorHandler:响应错误处理器,负责将 http 响应错误转换为 spring IOException 异常。
- 该类通过聚合 HttpMEssageConverter 类来进行异常转换。
-
HttpMessageConverter:http 消息转换器。负责处理请求/响应的消息转换,即消息的读写操作或序列化与反序列化。
- 在消息转换时,会涉及到 MediaType 的选择顺序问题:
- 首先看 @RequestMapping 注解上是否指定(如 produces = “application/json”),亦或是 response 的 ContentType 属性。
- 其次看 request 的 header 中是否指定 Accept。
- 最后看 HttpMessageConverter 的先后顺序,谁支持就使用谁。
- 对于 json 消息的转换,其底层依赖于各种序列化/反序列化库,如 jackson、gson、fastjson 等,同时,spring web 针对不同库提供了消息转换器具体实现:
- MappingJackson2HttpMessageConverter:利用 jackson 库实现的消息转换器。注:spring 框架中默认使用 jackson 进行序列化/反序列化。
- GsonHttpMessageConverter:利用 Google Gson 库实现的消息转换器。
- FastJsonHttpMessageConverter:alibaba 基于 fastjson 库实现的消息转换器。注:该实现由 alibaba 提供,并非 spring web。
- ByteArrayHttpMessageConverter:针对字节数组实现的消息转换器。读取支持所有类型,写入支持二进制流类型,即 Content-Type: application/octet-stream。
- StringHttpMessageConverter:针对字符串实现的消息转换器。读取支持所有类型,写入支持纯文本类型,即 Content-Type: text/plain。
- 在消息转换时,会涉及到 MediaType 的选择顺序问题:
-
RestTemplateBuilder:由 spring boot 提供,用来配置和构建 RestTemplate 的构建器工具类。
- 提供了多种便捷方法,如注册消息转换器方法、配置错误处理器方法、设置 URI 模板处理器方法等。
- spring boot 已通过 RestTemplateAutoConfiguration 自动配置类将该类实例注册为 ioc Bean 实例,故可直接通过依赖注入来使用。
2.3 xxxForObject() 与 xxxForEntity()
xxxForObject() 与 xxxForEntity() 区别如下:
| xxxForObject() | xxxForEntity() | |
|---|---|---|
| 返回值类型 | 直接返回反序列化后的业务对象 T | 返回包装对象 ResponseENtity< T> |
| HTTP 元数据访问 | 无法获取访问响应头/状态等信息 | 可通过 getHeaders() 或 getStatusCode() 等方法获取 |
| 异常处理 | 非 2xx 状态码直接抛出异常 | 可先获取响应对象 ResponseENtity< T> 再手动校验状态码 |
| 适用场景 | 仅需响应体的简单场景 | 需要完整控制响应的复杂场景 |
3 使用姿势
3.1 ResponseCode 与 APIResponse
-
ResponseCode
public enum ResponseCode { /** * base code */ SUCCESS(1, "请求成功!"), FAILURE(-1, "请求失败!"), SYSTEM_ERROR(-1, "系统异常!"), PARAMS_ERROR(-1, "参数不能为空!"), DATA_DOES_NOT_EXIST(-1, "数据不存在!"), /** * login or register */ ACCOUNT_OR_PASSWORD_ERROR(10100, "账号或密码错误!"), ACCOUNT_DOES_NOT_EXIST(10101, "账号不存在,请先注册!"), ; private final int code; private final String message; ResponseCode(int code, String message) { this.code = code; this.message = message; } public int getCode() { return code; } public String getMessage() { return message; } } -
APIResponse
@Data public class APIResponse<T> { private int code; private String message; private T data; public APIResponse() { this(ResponseCode.SUCCESS, null); } public APIResponse(int code, String message, T data) { this.code = code; this.message = message; this.data = data; } public APIResponse(ResponseCode responseCode, T data) { this.code = responseCode.getCode(); this.message = responseCode.getMessage(); this.data = data; } public static <T> APIResponse<T> success() { return success(ResponseCode.SUCCESS); } public static <T> APIResponse<T> success(T data) { return success(ResponseCode.SUCCESS, data); } public static <T> APIResponse<T> success(int code, String message) { return success(code, message, null); } public static <T> APIResponse<T> success(String message, T data) { return success(ResponseCode.SUCCESS.getCode(), message, data); } public static <T> APIResponse<T> success(int code, String message, T data) { return new APIResponse<>(code, message, data); } public static <T> APIResponse<T> success(ResponseCode responseCode) { return success(responseCode, null); } public static <T> APIResponse<T> success(ResponseCode responseCode, T data) { return new APIResponse<>(responseCode, data); } public static <T> APIResponse<T> failure() { return failure(ResponseCode.FAILURE.getMessage()); } public static <T> APIResponse<T> failure(String message) { return failure(ResponseCode.FAILURE.getCode(), message); } public static <T> APIResponse<T> failure(int code, String message) { return failure(code, message, null); } public static <T> APIResponse<T> failure(int code, String message, T data) { return new APIResponse<>(code, message, data); } public static <T> APIResponse<T> failure(ResponseCode responseCode) { return failure(responseCode, null); } public static <T> APIResponse<T> failure(ResponseCode responseCode, T data) { return new APIResponse<>(responseCode, data); } }
3.2 GET
-
示例一:
-
接口示例:
@GetMapping("/one/{id}/{name}") public APIResponse<Object> one(@PathVariable("id") long id, @PathVariable("name") String name) { return APIResponse.success(id + name); } -
调用示例:
String url = "http://ip:port/test/test/one/{id}/{name}"; RestTemplate restTemplate = new RestTemplate(); // 方式一 APIResponse response = restTemplate.getForObject(url, APIResponse.class, 1, "zed"); // 方式二 Map<String, Object> params = new HashMap<>(); params.put("id", 1); params.put("name", "Zed"); APIResponse response = restTemplate.getForObject(url, APIResponse.class, params);
-
-
示例二:
-
接口示例:
@GetMapping("/two") public APIResponse<RequestVo> two(RequestVo requestVo) { return APIResponse.success(requestVo); } -
调用示例:
String url = "http://ip:port/test/test/two?id={id}&name={name}"; RestTemplate restTemplate = new RestTemplate(); // 方式一 APIResponse response = restTemplate.getForObject(url, APIResponse.class, 1, "zed"); // 方式二 Map<String, Object> params = new HashMap<>(); params.put("id", 1); params.put("name", "Zed"); APIResponse response = restTemplate.getForObject(url, APIResponse.class, params);
-
-
示例三:
-
接口示例:
@GetMapping("/three") public APIResponse<Object> three(@RequestParam("id") long id, @RequestParam("name") String name) { return APIResponse.success(id + name); } -
调用示例:
String url = "http://ip:port/test/test/three?id={id}&name={name}"; RestTemplate restTemplate = new RestTemplate(); // 方式一 APIResponse response = restTemplate.getForObject(url, APIResponse.class, 1, "zed"); // 方式二 Map<String, Object> params = new HashMap<>(); params.put("id", 1); params.put("name", "Zed"); APIResponse response = restTemplate.getForObject(url, APIResponse.class, params);
-
-
示例四:
-
接口示例:
@GetMapping("/four/{id}") public APIResponse<Object> four(@PathVariable("id") long id, @RequestParam("name") String name) { return APIResponse.success(id + name); } -
调用示例:
String url = "http://ip:port/test/test/four/{id}?name={name}"; RestTemplate restTemplate = new RestTemplate(); // 方式一 APIResponse response = restTemplate.getForObject(url, APIResponse.class, 1, "zed"); // 方式二 Map<String, Object> params = new HashMap<>(); params.put("id", 1); params.put("name", "Zed"); APIResponse response = restTemplate.getForObject(url, APIResponse.class, params);
-
3.3 POST
-
示例一:
-
接口示例:
@PostMapping("/five/{id}/{name}") public APIResponse<Object> five(@PathVariable("id") long id, @PathVariable("name") String name) { return APIResponse.success(id + name); } -
调用示例:
String url = "http://ip:port/test/test/five/{id}/{name}"; RestTemplate restTemplate = new RestTemplate(); // 方式一 APIResponse response = restTemplate.postForObject(url, null, APIResponse.class, 1, "zed"); // 方式二 Map<String, Object> params = new HashMap<>(); params.put("id", 1); params.put("name", "Zed"); APIResponse response = restTemplate.postForObject(url, null, APIResponse.class, params);
-
-
示例二:
-
接口示例:
@PostMapping("/six") public APIResponse<RequestVo> six(RequestVo requestVo) { return APIResponse.success(requestVo); } -
调用示例:
String url = "http://ip:port/test/test/six?id={id}&name={name}"; RestTemplate restTemplate = new RestTemplate(); // 方式一 APIResponse response = restTemplate.postForObject(url, null, APIResponse.class, 1, "zed"); // 方式二 Map<String, Object> params = new HashMap<>(); params.put("id", 1); params.put("name", "Zed"); APIResponse response = restTemplate.postForObject(url, null, APIResponse.class, params);
-
-
示例三:
-
接口示例:
@PostMapping("/seven") public APIResponse<Object> seven(@RequestParam("id") long id, @RequestParam("name") String name) { return APIResponse.success(id + name); } -
调用示例:
String url = "http://ip:port/test/test/seven?id={id}&name={name}"; RestTemplate restTemplate = new RestTemplate(); // 方式一 APIResponse response = restTemplate.postForObject(url, null, APIResponse.class, 1, "zed"); // 方式二 Map<String, Object> params = new HashMap<>(); params.put("id", 1); params.put("name", "Zed"); APIResponse response = restTemplate.postForObject(url, null, APIResponse.class, params);
-
-
示例四:
-
接口示例:
@PostMapping("/eight/{id}") public APIResponse<Object> eight(@PathVariable("id") long id, @RequestParam("name") String name) { return APIResponse.success(id + name); } -
调用示例:
String url = "http://ip:port/test/test/eight/{id}?name={name}"; RestTemplate restTemplate = new RestTemplate(); // 方式一 APIResponse response = restTemplate.postForObject(url, null, APIResponse.class, 1, "zed"); // 方式二 Map<String, Object> params = new HashMap<>(); params.put("id", 1); params.put("name", "Zed"); APIResponse response = restTemplate.postForObject(url, null, APIResponse.class, params);
-
-
示例五:
-
接口示例:
@PostMapping("/nine") public APIResponse<Object> nine(@RequestBody RequestVo requestVo) { return APIResponse.success(requestVo); } -
调用示例:
String url = "http://ip:port/test/test/nine"; RestTemplate restTemplate = new RestTemplate(); // 方式一 Map<String, Object> params = new HashMap<>(); params.put("id", 1); params.put("name", "Zed"); APIResponse response = restTemplate.postForObject(url, params, APIResponse.class); // 方式二 RequestVo requestVo = RequestVo.builder() .id(1L) .name("zed") .build(); APIResponse response = restTemplate.postForObject(url, requestVo, APIResponse.class);
-
-
示例六:
-
接口示例:
@PostMapping("/ten/{id}") public APIResponse<Object> ten(@PathVariable("id") long id, @RequestBody RequestVo requestVo) { return APIResponse.success(requestVo.toString() + id); } -
调用示例:
String url = "http://ip:port/test/test/ten/{id}"; RestTemplate restTemplate = new RestTemplate(); // 方式一 RequestVo requestVo = RequestVo.builder() .id(1L) .name("zed") .build(); APIResponse response = restTemplate.postForObject(url, requestVo, APIResponse.class, 2); // 方式二 Map<String, Object> params = new HashMap<>(); params.put("id", 11); RequestVo requestVo = RequestVo.builder() .id(1L) .name("zed") .build(); APIResponse response = restTemplate.postForObject(url, requestVo, APIResponse.class, params);
-
3.4 exchange() 与 execute()
exchange() 为高级封装方法,作用与 xxxForEntity() 类似,仅在参数表方面略有不同。execute() 为底层基础执行方法,较其它方法而言具有更大的灵活性。故,这俩不演示也罢!
4 RestTemplate 与 WebClient
在 spring 5.0 版本以后,官方推荐使用 WebClient 作为替代,RestTemplate 将在未来版本中被标记为过时。当然,对于简单的同步请求场景,RestTemplate 仍是最佳选择。若在微服务环境中,则应考虑使用声明式的 Feign 客户端。
RestTemplate 与 WebClient 区别如下:
| RestTemplate | WebClient | |
|---|---|---|
| 编程模型 | 同步阻塞 | 异步非阻塞 |
| 性能 | 较低(阻塞) | 较高(基于 Reactor) |
| 配置复杂度 | 简单 | 中等 |
| 功能特性 | 基础 HTTP 操作 | 流式处理、SSE 等高级特性 |
| spring 版本 | spring 3.0+ | spring 5.0+ |
1210

被折叠的 条评论
为什么被折叠?



