WebClient和RestTemplate确实是Spring框架中用于发送HTTP请求的两种主要工具,但它们在设计理念、使用场景以及性能上有所不同。
1. RestTemplate
RestTemplate是一个较早的、基于阻塞IO的客户端库,用于发送各种类型的HTTP请求。它提供了一种模板化的方式来执行HTTP请求,支持多种HTTP方法(GET, POST, PUT, DELETE等)和多种数据类型(JSON, XML等)。RestTemplate的核心优点在于其简单易用,适合处理较为简单的HTTP请求。
特点:
- 阻塞式:每次请求都会阻塞直到响应返回,不适合高并发场景。
- 灵活性:支持多种HTTP方法和媒体类型,可以通过配置自定义消息转换器。
- 传统API:使用方法链式调用来构建请求,但API设计相对不够流畅。
RestTemplate 代码示例
首先,确保在配置类中定义一个 RestTemplate
bean:
@Configuration
public class AppConfig {
@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
使用RestTemplate发送POST 请求调用另一个微服务,并携带请求头
@RestController
public class UserController {
private static final Logger log = LoggerFactory.getLogger(UserController.class);
@Autowired
private UserService userService;
@Autowired
private RestTemplate restTemplate;
@PutMapping("/insert")
public User update(@RequestBody User user) {
// 示例:使用RestTemplate调用另一个微服务,并携带请求头
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.setBearerAuth("your-token"); // 设置Authorization头
HttpEntity<User> requestEntity = new HttpEntity<>(user, headers);
String response = restTemplate.postForObject(
"http://localhost:8080/user/insert1",
requestEntity,
String.class);
log.debug("Response from insert1: {}", response);
return user;
}
@Transactional
@PostMapping("/insert1")
public User update1(@RequestBody User user) {
userService.updateById(user);
return user;
}
}
使用 RestTemplate
发送 GET
请求
@RestController
public class UserController {
private static final Logger log = LoggerFactory.getLogger(UserController.class);
@Autowired
private UserService userService;
@Autowired
private RestTemplate restTemplate;
@PutMapping("/insert")
public User update(@RequestBody User user) {
// 示例:使用RestTemplate调用另一个微服务,并携带请求头
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.setBearerAuth("your-token"); // 设置Authorization头
HttpEntity<Void> requestEntity = new HttpEntity<>(headers);
String url = String.format("http://localhost:8080/user/insert1?age=%d&address=%s&name=%s&id=%d",
user.getAge(), user.getAddress(), user.getName(), user.getId());
ResponseEntity<String> response = restTemplate.exchange(
url,
HttpMethod.GET,
requestEntity,
String.class);
log.debug("Response from insert1: {}", response.getBody());
return user;
}
@Transactional
@GetMapping("/insert1")
public User update1(User user) {
userService.updateById(user);
return user;
}
}
2. WebClient
WebClient是Spring 5引入的新一代非阻塞的、响应式HTTP客户端,它基于Reactor项目构建。WebClient设计用于异步和响应式编程模型,特别适合微服务架构和高并发场景。
特点:
- 响应式:基于事件驱动和异步调用,可以处理大量并发请求,减少线程开销。
- 流式处理:支持数据流处理,能够高效处理大文件或长连接场景。
- 流畅API:提供了更加流畅的API设计,使得构建复杂的HTTP请求更为直观。
- 可组合性:请求和响应可以像函数式编程一样组合,易于创建复杂的业务逻辑。
WebClient代码示例
第一步 添加依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
<scope>compile</scope>
</dependency>
第二步添加配置类
package com.itheima.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.reactive.function.client.WebClient;
@Configuration
public class WebClientConfig {
@Bean
public WebClient webClient() {
return WebClient.create();
}
}
使用webClient发送GET请求
@PutMapping("/insert") // 将 HTTP PUT 请求映射到该方法
public User update(User user) {
// 记录日志,打印传入的 user 对象
log.info("update method called with user: {}", user);
// 使用 WebClient 调用另一个微服务
webClient.get() // 准备一个 GET 请求
.uri(uriBuilder -> uriBuilder
.scheme("http") // 设置协议为 http
.host("localhost") // 设置主机名为 localhost
.port(8080) // 设置端口号为 8080
.path("/user/insert1") // 设置路径为 /user/insert1
// 设置查询参数,使用传入的 user 对象的属性值
.queryParam("age", user.getAge())
.queryParam("address", user.getAddress())
.queryParam("name", user.getName())
.queryParam("id", user.getId())
.build()) // 构建完整的 URI
.retrieve() // 发送请求并准备检索响应体
.bodyToMono(String.class) // 将响应体转换为 Mono<String>
.timeout(Duration.ofSeconds(5)) // 设置请求超时时间为 5 秒
.retryWhen(Retry.backoff(3, Duration.ofSeconds(1))) // 设置重试机制,最多重试 3 次,每次间隔 1 秒
.subscribe(response -> log.info("Response from insert1: {}", response)); // 订阅响应,打印响应日志
// 返回传入的 user 对象
return user;
}
}
使用webClient发送POST请求
@PutMapping("/insert")
public User update(User user){
// 示例:使用webClient调用另一个微服务
webClient.post()
.uri(uriBuilder -> uriBuilder
.scheme("http")
.host("localhost")
.port(8080)
.path("/user/insert1")
.build())
.bodyValue(user)
.retrieve()
.bodyToMono(String.class)
.timeout(Duration.ofSeconds(5))
.retryWhen(Retry.backoff(10, Duration.ofSeconds(1))) // 设置重试机制
.subscribe(response -> log.debug("Response from insert1: {}", response));
return user;
}
@Transactional
@PostMapping("/insert1")
public User update1(@RequestBody User user){
userService.updateById(user);
return user;
}
选择建议
- 如果你的应用是基于传统的同步和阻塞IO模型,且对性能要求不高,RestTemplate可能是一个合适的选择。
- 如果你的应用需要处理高并发、大数据量的请求,或者你正在构建响应式微服务架构,WebClient将是一个更优的选择。
总结
两者都可以发送HTTP请求,但WebClient代表了未来的发展方向,尤其是在响应式编程和微服务领域。随着Spring框架的发展,WebClient的功能和社区支持都在不断加强,成为处理HTTP请求的首选工具。然而,对于不需要响应式特性的简单应用,RestTemplate仍然是一个简单有效的解决方案。