5858 字
约 19 分钟
0
Spring Boot 整合 RestTemplate 入门:从发送 GET 请

Spring Boot 整合 RestTemplate 入门:从发送 GET 请求到项目实战

在实际 Java 项目中,我们经常会遇到这样的需求:

用户服务
    ↓
调用
    ↓
订单服务

或者:

自己的系统
    ↓
HTTP 请求
    ↓
第三方接口

例如:

查询天气

调用短信服务

调用支付平台

调用地图 API

调用公司内部其他服务

这些场景本质上都在做一件事情:

Java 程序主动向另外一个 HTTP 服务发送请求,并获取响应数据。

在 Spring 体系中,RestTemplate 就是非常经典的一种 HTTP 客户端工具。


一、RestTemplate 是什么?

RestTemplate 是 Spring Framework 提供的一个同步 HTTP 客户端。

它用于帮助 Java 程序访问 HTTP / RESTful 接口。

例如浏览器访问:

GET /users/1001

可以获得一个用户。

那么 Java 程序也可能需要主动发送:

GET http://user-service/users/1001

这时候就可以使用:

RestTemplate

简单理解:

浏览器
    ↓
发送 HTTP 请求
    ↓
服务器

而 RestTemplate 做的是:

Java 程序
    ↓
RestTemplate
    ↓
发送 HTTP 请求
    ↓
另外一个服务器

所以可以把 RestTemplate 理解成:

一个帮助 Java 程序发送 HTTP 请求的 Spring 工具类。


二、为什么需要 RestTemplate?

如果完全不用 Spring 提供的 HTTP 客户端,我们当然也可以自己处理 HTTP 请求。

但自己写时往往需要关心很多底层细节:

创建 HTTP 连接

指定请求方法

设置 URL

设置 Header

设置 Content-Type

序列化 JSON

发送 Body

读取响应状态码

读取响应 Header

读取响应 Body

将 JSON 转成 Java 对象

异常处理

关闭连接

如果每调用一个接口都自己处理这些细节,代码会非常繁琐。

RestTemplate 对这些操作进行了进一步封装。

例如:

User user = restTemplate.getForObject(
        "http://localhost:8080/users/1",
        User.class
);

只需要一段很短的代码,就可以完成:

发送 GET 请求
    ↓
接收 JSON
    ↓
JSON 反序列化
    ↓
转换 User 对象

这就是 RestTemplate 最大的价值:

对 HTTP 请求调用进行封装,让开发人员更加专注于业务逻辑。


三、RestTemplate 的主要特点

RestTemplate 最明显的特点是:

简单
同步
模板式 API

它支持常见 HTTP 方法:

GET

POST

PUT

DELETE

HEAD

OPTIONS

还能够处理:

请求头

请求体

响应状态码

响应头

JSON 对象

泛型结果

文件上传

文件下载

认证

拦截器

所以在很多传统 Spring Boot 项目中,你都会看到它。


四、什么叫“同步 HTTP 客户端”?

这是学习 RestTemplate 时必须理解的概念。

假设:

A 服务

调用:

B 服务

代码:

User user = restTemplate.getForObject(url, User.class);

整个流程:

A 服务

    ↓

发送请求给 B

    ↓

等待……

    ↓

B 处理请求

    ↓

返回结果

    ↓

A 继续执行下面代码

也就是说:

B 没有返回结果之前,当前调用线程通常会等待。

例如:

System.out.println("1");

User user = restTemplate.getForObject(url, User.class);

System.out.println("2");

执行顺序:

打印 1

↓

发送 HTTP 请求

↓

等待服务器响应

↓

获得响应

↓

打印 2

这就是:

同步调用

也是 RestTemplate 非常重要的特点。


五、RestTemplate 在项目中什么时候使用?

RestTemplate 常见于:

调用第三方 HTTP API

调用内部服务

调用微服务接口

调用短信服务

调用支付接口

调用地图服务

调用文件服务

调用认证服务

例如系统中有:

order-service

user-service

订单服务查询订单时,需要补充用户信息。

可能产生:

order-service
      ↓
HTTP
      ↓
user-service

代码可能类似:

User user = restTemplate.getForObject(
        "http://user-service/users/" + userId,
        User.class
);

六、Spring Boot 如何整合 RestTemplate?

首先创建配置类。

@Configuration
public class RestTemplateConfig {

    @Bean
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}

这样 RestTemplate 就进入了 Spring IOC 容器。

之后在 Service 中可以注入:

@Service
public class UserService {

    private final RestTemplate restTemplate;

    public UserService(RestTemplate restTemplate) {
        this.restTemplate = restTemplate;
    }
}

然后就可以使用:

restTemplate

发送 HTTP 请求。


七、为什么要注册成 Bean?

你当然可以直接:

RestTemplate restTemplate = new RestTemplate();

但是在 Spring Boot 项目中,更推荐统一交给 Spring 管理。

原因是后续我们往往还需要配置:

超时时间

拦截器

日志

认证

底层 HTTP Client

错误处理器

如果所有地方都:

new RestTemplate();

配置就会非常分散。

例如:

UserService
    ↓
new RestTemplate()

OrderService
    ↓
new RestTemplate()

PayService
    ↓
new RestTemplate()

以后修改超时时间,需要修改很多地方。

而 Bean:

Spring IOC
    ↓
RestTemplate
    ↓
统一配置

更加方便维护。


八、第一个 GET 请求

假设我们有接口:

GET http://localhost:8080/api/users/1

返回:

{
  "id": 1,
  "name": "张三",
  "age": 20
}

定义 Java 对象:

public class User {

    private Long id;

    private String name;

    private Integer age;

    // getter/setter
}

使用:

User user = restTemplate.getForObject(
        "http://localhost:8080/api/users/1",
        User.class
);

这时候 RestTemplate 会帮助完成:

HTTP Response
      ↓
JSON
      ↓
Jackson
      ↓
User

最终:

System.out.println(user.getName());

可以得到:

张三

九、getForObject

getForObject() 是 RestTemplate 中非常常用的方法。

结构可以理解为:

getForObject(
    请求地址,
    返回类型
)

例如:

String result = restTemplate.getForObject(
        "http://localhost:8080/hello",
        String.class
);

如果服务器返回:

hello world

那么:

result

就是:

hello world

如果服务器返回 JSON:

{
  "id": 1,
  "name": "张三"
}

可以:

User user = restTemplate.getForObject(
        url,
        User.class
);

十、GET 请求携带路径参数

例如:

GET /users/{id}

可以:

User user = restTemplate.getForObject(
        "http://localhost:8080/users/{id}",
        User.class,
        1
);

这里:

{id}

最终会替换成:

1

实际请求:

http://localhost:8080/users/1

也可以使用 Map:

Map<String, Object> params = new HashMap<>();

params.put("id", 1);

User user = restTemplate.getForObject(
        "http://localhost:8080/users/{id}",
        User.class,
        params
);

十一、GET 请求携带 Query 参数

假设接口:

GET /users?page=1&size=10

最简单可以:

String url =
        "http://localhost:8080/users?page=1&size=10";

String result = restTemplate.getForObject(
        url,
        String.class
);

但是参数越来越多以后,不建议手动字符串拼接。

例如:

URI uri = UriComponentsBuilder
        .fromHttpUrl("http://localhost:8080/users")
        .queryParam("page", 1)
        .queryParam("size", 10)
        .build()
        .toUri();

然后:

String result =
        restTemplate.getForObject(uri, String.class);

这样 URL 构造会更加清晰。


十二、getForObject 和 getForEntity 有什么区别?

除了:

getForObject()

还有:

getForEntity()

例如:

ResponseEntity<User> response =
        restTemplate.getForEntity(
                "http://localhost:8080/users/1",
                User.class
        );

这时候得到的不是单纯:

User

而是:

ResponseEntity<User>

里面包含:

HTTP 状态码

HTTP Header

HTTP Body

例如:

HttpStatusCode statusCode = response.getStatusCode();

HttpHeaders headers = response.getHeaders();

User user = response.getBody();

所以可以简单理解:

getForObject
    ↓
我只关心响应 Body


getForEntity
    ↓
我不仅关心 Body
还关心 Status / Header

十三、POST 请求

假设接口:

POST /users

请求 Body:

{
  "name": "张三",
  "age": 20
}

可以:

UserRequest request = new UserRequest();

request.setName("张三");
request.setAge(20);

User result = restTemplate.postForObject(
        "http://localhost:8080/users",
        request,
        User.class
);

这里 RestTemplate 会:

UserRequest
    ↓
JSON 序列化
    ↓
HTTP Request Body
    ↓
发送 POST

服务器响应:

JSON
    ↓
User

十四、postForObject

可以简单记:

POST
+
只关心返回 Body

使用:

User user = restTemplate.postForObject(
        url,
        request,
        User.class
);

三个核心参数:

url

request

responseType

也就是:

请求哪里?

发送什么?

返回什么?

十五、postForEntity

如果我们还需要:

状态码

响应 Header

可以:

ResponseEntity<User> response =
        restTemplate.postForEntity(
                url,
                request,
                User.class
        );

然后:

response.getStatusCode();

response.getHeaders();

response.getBody();

十六、如何设置 Header?

这是项目里非常常见的操作。

例如接口要求:

Authorization: Bearer xxx

或者:

Content-Type: application/json

这时候可以使用:

HttpHeaders

例如:

HttpHeaders headers = new HttpHeaders();

headers.setContentType(MediaType.APPLICATION_JSON);

headers.setBearerAuth(token);

然后构造:

HttpEntity

例如:

HttpEntity<UserRequest> entity =
        new HttpEntity<>(request, headers);

这时候:

HttpEntity

里面同时包含:

Header
+
Body

十七、HttpEntity 到底是什么?

很多初学者看到:

HttpEntity

很容易迷糊。

可以直接这么理解:

HTTP Request

├── Header
└── Body

而:

HttpEntity

就是帮你把:

Header + Body

封装起来。

例如:

HttpHeaders headers = new HttpHeaders();

headers.setBearerAuth(token);

UserRequest request = new UserRequest();

HttpEntity<UserRequest> entity =
        new HttpEntity<>(request, headers);

相当于准备:

Authorization: Bearer xxx
Content-Type: application/json

{
    ...
}

十八、exchange 为什么特别重要?

如果你真正开始在项目里使用 RestTemplate,很快就会遇到:

exchange()

因为它非常灵活。

基本结构:

restTemplate.exchange(
        url,
        httpMethod,
        requestEntity,
        responseType
);

例如:

ResponseEntity<User> response =
        restTemplate.exchange(
                url,
                HttpMethod.GET,
                entity,
                User.class
        );

四个参数可以理解成:

url
    ↓
请求哪里


HttpMethod
    ↓
GET / POST / PUT / DELETE


HttpEntity
    ↓
Header + Body


User.class
    ↓
返回什么类型

十九、exchange 发送带 Token 的 GET 请求

例如:

HttpHeaders headers = new HttpHeaders();

headers.setBearerAuth(token);

HttpEntity<Void> entity =
        new HttpEntity<>(headers);

然后:

ResponseEntity<User> response =
        restTemplate.exchange(
                "http://localhost:8080/users/1",
                HttpMethod.GET,
                entity,
                User.class
        );

实际请求大概:

GET /users/1

Authorization: Bearer xxx

这就是项目里很典型的使用场景。


二十、exchange 发送 POST 请求

例如:

UserRequest request = new UserRequest();

request.setName("张三");
request.setAge(20);

Header:

HttpHeaders headers = new HttpHeaders();

headers.setContentType(MediaType.APPLICATION_JSON);
headers.setBearerAuth(token);

封装:

HttpEntity<UserRequest> entity =
        new HttpEntity<>(request, headers);

发送:

ResponseEntity<User> response =
        restTemplate.exchange(
                url,
                HttpMethod.POST,
                entity,
                User.class
        );

完整流程:

Java Object
    ↓
HttpEntity
    ↓
Header + Body
    ↓
RestTemplate
    ↓
POST
    ↓
远程服务
    ↓
JSON Response
    ↓
ResponseEntity<User>

二十一、PUT 请求

RestTemplate 提供:

put()

例如:

restTemplate.put(
        "http://localhost:8080/users/1",
        request
);

需要注意:

put()

通常没有直接返回 Body。

如果想同时处理响应:

状态码

Header

Body

可以使用:

exchange()

例如:

ResponseEntity<User> response =
        restTemplate.exchange(
                url,
                HttpMethod.PUT,
                entity,
                User.class
        );

二十二、DELETE 请求

最简单:

restTemplate.delete(
        "http://localhost:8080/users/1"
);

同样,如果 DELETE 接口还需要:

Header

Token

Response Body

可以:

restTemplate.exchange(
        url,
        HttpMethod.DELETE,
        entity,
        Void.class
);

二十三、为什么项目里很多人直接用 exchange?

因为:

getForObject

getForEntity

postForObject

postForEntity

put

delete

都属于比较方便的快捷 API。

但是一旦需求变成:

自定义 Header

自定义 Method

携带 Token

处理响应状态

自定义 Body

泛型返回值

exchange() 会更加统一。

所以项目代码中经常看到:

restTemplate.exchange(...)

二十四、返回 List 怎么处理?

假设服务器返回:

[
  {
    "id": 1,
    "name": "张三"
  },
  {
    "id": 2,
    "name": "李四"
  }
]

很多人第一反应:

List<User>.class

但是 Java 不支持:

List<User>.class

因为存在:

泛型擦除

这时候可以使用:

ParameterizedTypeReference

例如:

ResponseEntity<List<User>> response =
        restTemplate.exchange(
                url,
                HttpMethod.GET,
                null,
                new ParameterizedTypeReference<List<User>>() {}
        );

然后:

List<User> users = response.getBody();

二十五、ParameterizedTypeReference 为什么存在?

因为 Java 运行时直接使用:

List.class

只能知道:

这是一个 List

但不知道:

List<User>

中的:

User

是什么。

所以:

ParameterizedTypeReference<List<User>>

可以帮助 Spring 保留完整泛型类型信息。

以后你遇到:

List<User>

PageResult<User>

Map<String, User>

这样的复杂返回类型,都可能需要使用它。


二十六、JSON 为什么可以自动变成 Java 对象?

例如 HTTP 返回:

{
  "id": 1,
  "name": "张三"
}

为什么:

restTemplate.getForObject(
        url,
        User.class
);

直接就变成:

User

其中一个重要机制就是:

HttpMessageConverter

在典型 Spring Boot JSON 场景中,会结合 Jackson 完成:

JSON
    ↓
Java Object

以及:

Java Object
    ↓
JSON

所以整个过程可以理解:

发送请求:

UserRequest
    ↓
HttpMessageConverter
    ↓
JSON
    ↓
HTTP


接收响应:

HTTP
    ↓
JSON
    ↓
HttpMessageConverter
    ↓
User

RestTemplate 帮你把这些转换过程隐藏起来了。


二十七、HTTP 调用一定要配置超时

这是项目开发里非常重要的一点。

假设:

order-service
    ↓
HTTP
    ↓
user-service

如果 user-service 卡死。

order-service 不能:

一直无限等待

否则请求越来越多:

Thread 1 等待

Thread 2 等待

Thread 3 等待

Thread 4 等待

...

最终可能拖垮自己的服务。

所以调用远程 HTTP 服务时通常需要考虑:

连接超时

读取超时

二十八、什么是连接超时?

例如:

A 服务
    ↓
连接
    ↓
B 服务

如果 B:

机器不存在

端口没启动

网络异常

连接迟迟建立不了。

这时候:

Connect Timeout

决定:

我最多等多久来建立连接。


二十九、什么是读取超时?

连接建立成功:

A → B

但是 B 处理:

数据库慢查询

死循环

下游超时

一直没有返回结果。

这时候:

Read Timeout

决定:

连接已经建立以后,我最多等待服务器响应多久。

简单区分:

Connect Timeout
=
连接都连不上


Read Timeout
=
连接上了
但是对方迟迟不给结果

三十、异常处理

HTTP 请求不一定都是:

200 OK

可能返回:

400

401

403

404

500

503

RestTemplate 调用过程中通常需要处理相关异常。

例如:

try {

    User user =
            restTemplate.getForObject(url, User.class);

} catch (HttpClientErrorException e) {

    // 4xx

} catch (HttpServerErrorException e) {

    // 5xx

} catch (RestClientException e) {

    // RestTemplate 相关异常

}

可以粗略理解:

4xx
    ↓
客户端请求问题


5xx
    ↓
远程服务器问题

但真实项目还需要结合具体状态码判断。


三十一、不要把所有异常直接吞掉

不推荐:

try {

    restTemplate.getForObject(url, User.class);

} catch (Exception e) {

}

这样发生问题以后:

没有日志

不知道哪个接口失败

不知道状态码

不知道请求地址

不知道为什么失败

排查非常困难。

至少应该考虑记录:

请求 URL

HTTP Method

响应状态码

错误信息

TraceId

但是注意:

密码

Authorization Token

身份证号

银行卡

敏感信息

不要直接打印到日志。


三十二、RestTemplate 拦截器

如果每个请求都需要:

Authorization

TraceId

公共 Header

日志

你肯定不希望每个 Service 都重复:

headers.set(...)

这时候可以使用:

ClientHttpRequestInterceptor

例如概念上:

RestTemplate
     ↓
Interceptor
     ↓
自动添加 Header
     ↓
HTTP Server

这样所有请求可以统一处理。


三十三、一个典型的 TraceId 拦截器

例如:

public class TraceInterceptor
        implements ClientHttpRequestInterceptor {

    @Override
    public ClientHttpResponse intercept(
            HttpRequest request,
            byte[] body,
            ClientHttpRequestExecution execution
    ) throws IOException {

        request.getHeaders()
               .add("X-Trace-Id", UUID.randomUUID().toString());

        return execution.execute(request, body);
    }
}

配置:

@Bean
public RestTemplate restTemplate() {

    RestTemplate restTemplate =
            new RestTemplate();

    restTemplate.getInterceptors()
                .add(new TraceInterceptor());

    return restTemplate;
}

以后:

所有 RestTemplate 请求

都可以自动携带:

X-Trace-Id

三十四、RestTemplate 在微服务中的位置

假设:

用户服务

订单服务

库存服务

支付服务

订单服务可能调用:

用户服务
库存服务
支付服务

传统情况下:

OrderService
    │
    ├── RestTemplate → UserService
    │
    ├── RestTemplate → StockService
    │
    └── RestTemplate → PaymentService

从本质上讲:

RestTemplate

解决的就是:

服务之间通过 HTTP 通信

的问题。


三十五、RestTemplate 和 Feign 有什么关系?

学习微服务时你可能还会遇到:

OpenFeign

例如 RestTemplate:

User user =
        restTemplate.getForObject(
                "http://user-service/users/" + id,
                User.class
        );

Feign 的思想更偏声明式:

@GetMapping("/users/{id}")
User getUser(@PathVariable Long id);

你只定义:

接口

框架帮你完成 HTTP 调用。

所以可以粗略理解:

RestTemplate
=
命令式调用


Feign
=
声明式调用

在 Spring Cloud 项目里,Feign 由于可读性和服务治理整合能力,经常更加常见。


三十六、RestTemplate 和 WebClient 有什么区别?

RestTemplate 最大特点:

同步
阻塞式

WebClient 则面向:

响应式

非阻塞

异步

流式处理

可以简单理解:

RestTemplate

请求
 ↓
线程等待
 ↓
响应
 ↓
继续执行

而 WebClient 可以支持:

请求
 ↓
不一定让线程一直傻等
 ↓
响应到达
 ↓
继续处理

如果项目是:

Spring WebFlux

高并发 I/O

响应式系统

Streaming

通常会更多考虑:

WebClient

三十七、RestTemplate 和 RestClient

现在学习 Spring HTTP 客户端还应该认识:

RestClient

RestClient 提供的是:

同步 HTTP 调用
+
更加现代的 Fluent API

例如思想上:

restClient.get()
          .uri("/users/{id}", id)
          .retrieve()
          .body(User.class);

对比 RestTemplate:

restTemplate.getForObject(
        url,
        User.class
);

二者都是同步客户端,但 API 风格不同。

对于新的 Spring 项目,应该关注 RestClient。


三十八、为什么现在还要学 RestTemplate?

既然有:

RestClient

WebClient

OpenFeign

为什么还需要学习 RestTemplate?

原因非常现实:

大量老项目仍然存在

大量教程仍然使用

很多公司内部系统仍然使用

维护历史代码必须能看懂

理解 HTTP 客户端原理非常有帮助

所以 RestTemplate 依然值得掌握。

但是学习目标应该调整:

会使用

能维护

能排错

能迁移

而不是:

所有新项目无脑 RestTemplate

三十九、一个真实项目案例

现在假设:

order-service

需要通过 HTTP 查询:

user-service

接口:

GET /users/{id}

返回:

{
  "id": 1001,
  "name": "张三"
}

首先配置:

@Configuration
public class RestTemplateConfig {

    @Bean
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}

User DTO:

public class UserDTO {

    private Long id;

    private String name;

    // getter setter
}

调用:

@Service
public class UserRemoteService {

    private final RestTemplate restTemplate;

    public UserRemoteService(
            RestTemplate restTemplate
    ) {
        this.restTemplate = restTemplate;
    }

    public UserDTO getUser(Long id) {

        String url =
                "http://localhost:8081/users/{id}";

        return restTemplate.getForObject(
                url,
                UserDTO.class,
                id
        );
    }
}

OrderService:

@Service
public class OrderService {

    private final UserRemoteService userRemoteService;

    public OrderService(
            UserRemoteService userRemoteService
    ) {
        this.userRemoteService = userRemoteService;
    }

    public OrderVO getOrder(Long orderId) {

        Order order = findOrder(orderId);

        UserDTO user =
                userRemoteService.getUser(
                        order.getUserId()
                );

        OrderVO vo = new OrderVO();

        vo.setOrderId(order.getId());

        vo.setUserName(user.getName());

        return vo;
    }
}

整个链路:

用户

 ↓

order-service

 ↓
查询订单 MySQL

 ↓
获得 userId

 ↓

RestTemplate

 ↓ HTTP

user-service

 ↓

查询用户

 ↓

返回 JSON

 ↓

UserDTO

 ↓

OrderVO

 ↓

用户

这就是 RestTemplate 非常典型的实际使用方式。


四十、项目中不要到处直接写 RestTemplate

不推荐:

@Service
public class OrderService {

    public void xxx() {

        restTemplate.getForObject(...);

        restTemplate.postForObject(...);

        restTemplate.exchange(...);

    }

}

然后订单业务逻辑和 HTTP 调用完全混在一起。

更推荐进行一层封装:

OrderService
    ↓
UserRemoteClient
    ↓
RestTemplate
    ↓
User Service

例如:

@Component
public class UserRemoteClient {

    private final RestTemplate restTemplate;

    public UserRemoteClient(
            RestTemplate restTemplate
    ) {
        this.restTemplate = restTemplate;
    }

    public UserDTO findById(Long id) {

        return restTemplate.getForObject(
                "http://user-service/users/{id}",
                UserDTO.class,
                id
        );
    }
}

业务层:

UserDTO user =
        userRemoteClient.findById(userId);

这样:

业务逻辑

和:

远程 HTTP 调用

被隔离开。

后面哪怕从:

RestTemplate

迁移到:

RestClient

业务层影响也会小很多。


四十一、项目中更应该注意什么?

真正生产环境使用 RestTemplate 时,不能只关注:

请求能不能发出去

而应该同时考虑:

连接超时

读取超时

异常处理

重试策略

连接池

认证信息

TraceId

日志

监控

熔断

限流

服务降级

比如:

Order Service
    ↓
Payment Service

Payment Service 宕机了。

如果每个 Order 请求都:

等待几十秒

最终可能把 Order Service 一起拖死。

这就是典型的:

故障传播

所以 HTTP 客户端真正进入微服务架构以后,需要结合:

Timeout

Retry

Circuit Breaker

Bulkhead

等服务治理能力。


四十二、重试不是越多越好

例如远程服务返回失败。

很多人第一反应:

那就重试 10 次

这是非常危险的。

假设远程服务已经压力过高。

原来:

1000 个请求

现在每个失败重试 3 次。

就可能瞬间变成:

3000+

额外请求。

服务可能更加撑不住。

另外:

POST 创建订单
POST 支付
POST 扣款

这种请求如果随便重试,还可能导致:

重复创建

重复扣款

所以重试必须考虑:

请求是否幂等

错误类型

重试次数

退避策略

四十三、常用 API 总结

RestTemplate 常用 API 可以整理成:

GET

getForObject()
getForEntity()


POST

postForObject()
postForEntity()


PUT

put()


DELETE

delete()


通用请求

exchange()
execute()

其中日常项目中最值得掌握:

getForObject

getForEntity

postForObject

exchange

尤其:

exchange()

使用非常广泛。


四十四、几个核心对象一定要分清

学习 RestTemplate 时最容易混的是:

RestTemplate

HttpHeaders

HttpEntity

ResponseEntity

可以这样理解:

RestTemplate
=
负责发送请求


HttpHeaders
=
HTTP 请求头 / 响应头


HttpEntity
=
Header + Request Body


ResponseEntity
=
Status + Header + Response Body

完整流程:

HttpHeaders
    +
Request Body
    ↓
HttpEntity
    ↓
RestTemplate
    ↓
HTTP Server
    ↓
ResponseEntity
    ↓
Status
Header
Body

把这个图理解以后,RestTemplate 基本就通了。


四十五、RestTemplate 知识体系

如果准备系统学习,可以按照这个顺序:

第一阶段

HTTP 基础
GET
POST
PUT
DELETE
Header
Body
Status Code


第二阶段

RestTemplate
getForObject
getForEntity
postForObject
postForEntity


第三阶段

HttpHeaders
HttpEntity
ResponseEntity
exchange


第四阶段

JSON 序列化
HttpMessageConverter
ParameterizedTypeReference


第五阶段

Timeout
Exception
Interceptor


第六阶段

服务间调用
Feign
RestClient
WebClient


第七阶段

Retry
Circuit Breaker
服务降级
微服务治理

这样学习不会停留在:

会复制一段 RestTemplate 代码

而是能够真正理解:

一个 HTTP 调用在项目里面是怎么运行的。

总结

RestTemplate 本质上就是:

Spring 提供的一个同步 HTTP 客户端,用来帮助 Java 应用访问其他 HTTP 服务。

最典型的使用流程:

Java Service
      ↓
准备 URL
      ↓
准备 Header
      ↓
准备 Body
      ↓
HttpEntity
      ↓
RestTemplate
      ↓
HTTP Request
      ↓
Remote Service
      ↓
HTTP Response
      ↓
ResponseEntity
      ↓
Java Object

真正入门以后,需要重点理解下面几个关系:

全文调用能力
    ↓
RestTemplate


请求头
    ↓
HttpHeaders


Header + Body
    ↓
HttpEntity


Status + Header + Body
    ↓
ResponseEntity


复杂请求
    ↓
exchange()


JSON ↔ Java
    ↓
HttpMessageConverter

同时要建立一个现代 Spring 项目的认知:

维护老项目
    ↓
RestTemplate 很重要


新同步 HTTP 调用
    ↓
优先关注 RestClient


响应式 / 非阻塞 / 流式
    ↓
WebClient


Spring Cloud 声明式服务调用
    ↓
OpenFeign

所以学习 RestTemplate 最好的目标不是单纯背:

getForObject()
postForObject()
exchange()

而是彻底搞清楚:

一个 Java 服务
到底是如何通过 HTTP
调用另外一个服务的。

只要这个底层模型理解了,以后再学习:

RestClient
WebClient
Feign
Dubbo
RPC
微服务通信

都会容易很多。

Spring Boot 整合 RestTemplate 入门:从发送 GET 请
http://www.clxhxhhr.top/posts/401/
作者
clxstart
发布于
2026-09-01
许可协议
CC BY-NC-SA 4.0
评论
0 条
还没有评论,先写一条吧。
文章目录
目录