各位在Spring生态摸爬滚打的道友们!今天要解锁的是Spring 5的镇派绝学——WebClient!这货堪称响应式编程界的"御剑飞行术",比老旧的RestTemplate快出三个境界,还能轻松处理高并发请求!准备好迎接"异步非阻塞"的修仙新时代了吗? 🚀
一、筑基篇:初识WebClient
1.1 法宝祭炼(添加依赖)
<!-- Spring Boot WebFlux(已包含WebClient) -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
1.2 召唤本命法宝
// 基础召唤术(默认配置)
WebClient client = WebClient.create();
// 注入灵力版(推荐Bean方式)
@Bean
public WebClient webClient() {
return WebClient.builder()
.baseUrl("https://api.example.com")
.defaultHeader("User-Agent", "WebClient-Discovery")
.build();
}
二、金丹篇:基础请求术
2.1 GET请求(探查天地灵气)
Mono<String> response = webClient.get()
.uri("/users/1")
.retrieve()
.bodyToMono(String.class);
// 同步获取结果(仅测试用,实际应该用响应式流)
System.out.println("响应内容:" + response.block());
2.2 POST请求(传送灵力)
User user = new User("张无忌", 25);
Mono<User> createdUser = webClient.post()
.uri("/users")
.contentType(MediaType.APPLICATION_JSON)
.bodyValue(user)
.retrieve()
.bodyToMono(User.class);
createdUser.subscribe(user ->
System.out.println("创建用户成功,ID:" + user.getId())
);
三、元婴篇:高级神通
3.1 异步非阻塞(分身术)
Flux<User> users = webClient.get()
.uri("/users")
.retrieve()
.bodyToFlux(User.class);
// 配合响应式流处理(不会阻塞主线程)
users.subscribe(
user -> System.out.println("收到用户:" + user.getName()),
error -> System.err.println("渡劫失败:" + error.getMessage()),
() -> System.out.println("所有用户接收完毕!")
);
3.2 文件上传(乾坤大挪移)
MultipartBodyBuilder builder = new MultipartBodyBuilder();
builder.part("file", new FileSystemResource("avatar.jpg"));
builder.part("name", "张无忌");
Mono<String> result = webClient.post()
.uri("/upload")
.contentType(MediaType.MULTIPART_FORM_DATA)
.body(BodyInserters.fromMultipartData(builder.build()))
.retrieve()
.bodyToMono(String.class);
四、化神篇:异常处理
4.1 错误状态码处理(渡劫护盾)
Mono<User> user = webClient.get()
.uri("/users/99")
.retrieve()
.onStatus(HttpStatus::is4xxClientError, response ->
Mono.error(new RuntimeException("客户端错误: " + response.statusCode()))
)
.onStatus(HttpStatus::is5xxServerError, response ->
Mono.error(new RuntimeException("服务器开小差了"))
)
.bodyToMono(User.class);
4.2 重试机制(不死之身)
Flux<User> users = webClient.get()
.uri("/users")
.retrieve()
.bodyToFlux(User.class)
.retryWhen(Retry.backoff(3, Duration.ofSeconds(1)) // 最多重试3次
.doOnError(e -> System.err.println("最终失败:" + e.getMessage()));
五、大乘篇:性能调优
5.1 连接池配置(灵气循环)
@Bean
public WebClient webClient() {
ConnectionProvider provider = ConnectionProvider.builder("myPool")
.maxConnections(500)
.pendingAcquireTimeout(Duration.ofSeconds(30))
.build();
HttpClient httpClient = HttpClient.create(provider)
.responseTimeout(Duration.ofSeconds(10));
return WebClient.builder()
.clientConnector(new ReactorClientHttpConnector(httpClient))
.build();
}
5.2 请求/响应日志(天眼通)
HttpClient httpClient = HttpClient.create()
.wiretap("reactor.netty.http.client.HttpClient",
LogLevel.DEBUG, AdvancedByteBufFormat.TEXTUAL);
WebClient client = WebClient.builder()
.clientConnector(new ReactorClientHttpConnector(httpClient))
.build();
六、实战心法
6.1 与Spring Security集成(护山大阵)
@Bean
public WebClient securedWebClient(ReactiveClientRegistrationRepository repo) {
ServerOAuth2AuthorizedClientExchangeFilterFunction oauth =
new ServerOAuth2AuthorizedClientExchangeFilterFunction(repo);
oauth.setDefaultOAuth2AuthorizedClient(true);
return WebClient.builder()
.filter(oauth)
.build();
}
// 使用自动携带令牌
Mono<String> data = securedWebClient.get()
.uri("/protected-data")
.retrieve()
.bodyToMono(String.class);
6.2 SSE(服务器推送事件)处理
Flux<String> eventStream = webClient.get()
.uri("/live-updates")
.accept(MediaType.TEXT_EVENT_STREAM)
.retrieve()
.bodyToFlux(String.class);
eventStream.subscribe(event ->
System.out.println("收到事件:" + event)
);
飞升指南:最佳实践
- 绝不阻塞:永远不要在响应式链中调用block()
- 资源回收:记得订阅返回的Mono/Flux
- 背压处理:大数据流使用limitRate()控制流速
- 超时配置:生产环境必须设置responseTimeout