1. 引言

在Spring生态系统中,RestTemplate是一个核心工具类。它的高级抽象让发送HTTP请求和处理响应变得异常简单

本文将深入探讨RestTemplate类中三个关键方法——*exchange()postForEntity()execute()*的核心差异。

2. 什么是RestTemplate

如前所述,RestTemplate是Spring框架中的实用工具类,专门简化HTTP消息发送与响应处理。它特别适合构建基础HTTP客户端,主要特性包括:

  • ✅ 支持所有标准HTTP动词(GET、POST等)
  • ✅ 兼容所有标准MIME类型(JSON、XML、表单编码等)
  • ✅ 提供高级API,直接操作Java对象,无需关心底层序列化细节
  • ✅ 可通过ClientHttpRequestInitializerClientHttpRequestInterceptor接口定制

2.1. 废弃警告

⚠️ 从Spring Framework 5开始,RestTemplate类正逐步被废弃。虽然它在Spring Framework 6中仍然存在,但维护团队明确表示不会再进行功能增强。

由于未来只会接受少量bug修复和安全更新,官方推荐改用WebClient。这个新类拥有更现代的API,支持同步、异步和流式处理场景。

3. RestTemplate基础用法

RestTemplate通过提供与HTTP动词同名的公共方法,让标准HTTP操作变得极其简单。

例如发送GET请求时,可以使用众多以getFor开头的重载方法。其他HTTP动词(POST、PUT、DELETE、HEAD、PATCH)也有类似的专用方法。

这些方法的结构高度一致,本质上只需要目标URL、请求体和响应体的表示形式。HTTP头等信息会自动处理。

虽然这些高级方法让HTTP客户端开发变得简单,但现实世界往往比HTTP规范更复杂。有时我们需要构建不符合标准模板的HTTP请求,这时就需要用到RestTemplate提供的更底层方法。

4. 使用*exchange()postForEntity()execute()*方法

虽然顶层专用方法能满足多数场景,但有时我们需要更精细控制RestTemplate生成的HTTP请求。这时*exchange()execute()*方法就派上用场了。

以创建图书数据库条目的POST请求为例,先定义请求体封装类:

class Book {
  String title;
  String author;
  int yearPublished;
}

下面分别用三种方法发送这个请求:

4.1. 使用*postForEntity()*方法

最简单的POST请求方式是postForEntity()。**只需提供URL和请求体,响应会自动解析为ResponseEntity对象**:

Book book = new Book(
  "Cruising Along with Java",
  "Venkat Subramaniam",
  2023);

 ResponseEntity<Book> response = restTemplate.postForEntity(
  "https://api.bookstore.com", 
  book, 
  Book.class);

这个例子中,我们创建新书对象并发送到服务器,响应被解析回Book对象。注意只需提供远程URL、请求对象和响应类型类,HTTP头等细节由RestTemplate自动处理

4.2. 使用*exchange()*方法

第二种方式是使用*exchange()*方法:

Book book = new Book(
  "Effective Java",
  "Joshua Bloch",
  2001);

HttpHeaders headers = new HttpHeaders();
headers.setBasicAuth("username", "password");

ResponseEntity<Book> response = restTemplate.exchange(
  "https://api.bookstore.com",
  HttpMethod.POST,
  new HttpEntity<>(book, headers),
  Book.class);

核心区别在于:请求体被包装在HttpEntity中,允许显式设置HTTP头

另一个显著差异是*exchange()*的通用性——它支持所有HTTP方法。因此URL后的第二个参数必须指定请求方法

4.3. 使用*execute()*方法

最后是execute()方法,这是最底层的实现。**实际上它是RestTemplate内部所有方法的最终调用入口**:

ResponseEntity<Book> response = restTemplate.execute(
    "https://api.bookstore.com",
    HttpMethod.POST,
    new RequestCallback() {
        @Override
        public void doWithRequest(ClientHttpRequest request) throws IOException {
            // 操作请求头和请求体
        }
    },
    new ResponseExtractor<ResponseEntity<Book>>() {
        @Override
        public ResponseEntity<Book> extractData(ClientHttpResponse response) throws IOException {
            // 操作响应并返回ResponseEntity
        }
    }
);

虽然仍需提供URL和HTTP方法,但其他部分完全不同。*因为execute()不直接处理请求/响应对象**,而是通过RequestCallbackResponseExtractor*接口让我们手动控制。

最大优势:对请求/响应对象拥有完全控制权
代价:代码更冗长,失去RestTemplate的自动化特性

RestTemplate也提供了工厂方法简化*execute()*使用:

Book book = new Book(
  "Reactive Spring",
  "Josh Long",
  2020);
        
RequestCallback requestCallback1 = restTemplate.httpEntityCallback(book);
RequestCallback requestCallback2 = restTemplate.httpEntityCallback(book, Book.class);

以及响应提取器工厂方法:

ResponseExtractor<ResponseEntity<Book>> responseExtractor = restTemplate.responseEntityExtractor(Book.class);

⚠️ 但若同时使用这两个工厂方法,就失去了使用*execute()的意义——不如直接用专用方法或exchange()*更简单。

5. 总结

本文探讨了RestTemplate发送POST请求的三种方式。首先使用专用方法*postForEntity()构建简洁请求,然后对比了exchange()execute()*两种替代方案。

虽然三种方法结果相同,但各有优劣:

  • *postForEntity()*:代码最简洁,但控制力最弱
  • *exchange()*:平衡了控制力和代码简洁性
  • *execute()*:控制力最强,但代码最冗长,牺牲了框架自动化特性

本文代码示例可在GitHub仓库中找到。


原始标题:Difference Between exchange(), postForEntity(), and execute() in RestTemplate | Baeldung