> 技术文档 > 什么是 WebClient 以及 Java 微服务如何使用 WebClient 进行通信?代码详细介绍

什么是 WebClient 以及 Java 微服务如何使用 WebClient 进行通信?代码详细介绍

在 Java 微服务中,服务之间经常需要通过 HTTP 进行通信。Spring Boot 提供了强大的非阻塞 HTTP 客户端工具 —— WebClient,用于替代传统的 RestTemplate。

一、什么是 WebClient?

WebClient 是 Spring WebFlux 中引入的一个响应式、非阻塞的 HTTP 客户端,用于发起 HTTP 请求(GET、POST、PUT、DELETE 等)并接收响应。

🔹 属于 Spring 5 的一部分,可用于同步和异步通信
🔹 支持响应式编程(Reactor)、也可以用于传统 MVC 项目

二、WebClient 与微服务通信的作用

在微服务架构中,每个服务都是独立运行的,因此:

  • 订单服务(Order)需要调用商品服务(Product)

  • 用户服务(User)需要调用认证服务(Auth)

这些调用通常使用 WebClient 发出 HTTP 请求完成服务间通信。

三、依赖配置

如果你使用的是 Spring Boot 项目,需要在 pom.xml 中添加以下依赖:

<!-- Spring Boot WebFlux 提供 WebClient --><dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-webflux</artifactId></dependency>

四、使用 WebClient 的基本方式

1. 创建 WebClient 实例

方式一:使用默认构建器

WebClient webClient = WebClient.create();

方式二:指定 base URL

WebClient webClient = WebClient.builder() .baseUrl(\"http://product-service\") .build();

也可以注入为 Spring Bean:

@Configurationpublic class WebClientConfig { @Bean public WebClient webClient() { return WebClient.builder().build(); }}

2. 发起请求(GET / POST / PUT / DELETE)

示例 1:GET 请求获取商品列表

List<String> products = webClient.get() .uri(\"http://localhost:8081/products\") .retrieve() .bodyToFlux(String.class) .collectList() .block(); // 阻塞获取数据(适合同步场景)

示例 2:POST 请求创建订单

OrderRequest request = new OrderRequest(\"product123\", 2);OrderResponse response = webClient.post() .uri(\"http://localhost:8082/orders\") .bodyValue(request) .retrieve() .bodyToMono(OrderResponse.class) .block(); // 或异步处理

五、使用 WebClient 异步响应式编程

public Mono<List<Product>> fetchProductsAsync() { return webClient.get() .uri(\"http://product-service/products\") .retrieve() .bodyToFlux(Product.class) .collectList(); // 返回 Mono<List>}

可与 Reactor 或 Project Reactor 配合使用,构建响应式流式处理。

六、与 Spring Cloud 结合使用(服务名调用 + 负载均衡)

如果你使用了 Spring Cloud 和 Eureka 注册中心,可以通过服务名称(而不是 IP 地址)访问目标服务。

✅ 添加依赖:

<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-loadbalancer</artifactId></dependency>

✅ 使用 @LoadBalanced 注入 WebClient

@Bean@LoadBalancedpublic WebClient.Builder loadBalancedWebClientBuilder() { return WebClient.builder();}

调用方式:

webClientBuilder.build() .get() .uri(\"http://product-service/products\") .retrieve() .bodyToFlux(Product.class);

📌 自动通过注册中心(如 Eureka)找到服务并进行负载均衡

七、错误处理(如 404, 500)

webClient.get() .uri(\"/products/123\") .retrieve() .onStatus(HttpStatus::is4xxClientError, response -> { return Mono.error(new RuntimeException(\"Client Error\")); }) .onStatus(HttpStatus::is5xxServerError, response -> { return Mono.error(new RuntimeException(\"Server Error\")); }) .bodyToMono(Product.class);

八、总结:为什么在微服务中推荐使用 WebClient?

特性 说明 非阻塞 / 响应式 提升性能,减少资源占用 灵活强大 支持各种 HTTP 请求方式和响应处理 替代 RestTemplate 未来推荐方式,Spring 官方建议迁移 可配合服务发现 与 Eureka、LoadBalancer 集成 支持异步响应 适合复杂的链式调用和并发调用场景

使用 Spring Boot + WebClient 实现 服务 A 调用服务 B 的完整示例,包括:

  • 服务 B 提供商品数据(Product Service)

  • 服务 A 调用服务 B 的接口获取商品信息(Order Service)

  • 使用 WebClient 实现服务间通信

简洁明了的代码结构,便于实际项目应用

场景说明

[Order Service] --通过 WebClient 调用--> [Product Service]

1. 服务 B(Product Service)

1.1 创建 ProductService 应用(端口 8081)

ProductController.java
@RestController@RequestMapping(\"/products\")public class ProductController { @GetMapping(\"/{id}\") public Product getProduct(@PathVariable String id) { return new Product(id, \"Sample Product\", 99.99); }}
Product.java
public class Product { private String id; private String name; private double price; // 构造器、Getter 和 Setter 略}

2. 服务 A(Order Service)

2.1 创建 OrderService 应用(端口 8080)

WebClientConfig.java
@Configurationpublic class WebClientConfig { @Bean public WebClient webClient() { return WebClient.builder() .baseUrl(\"http://localhost:8081\") // Product Service 地址 .build(); }}

ProductClientService.java

@Servicepublic class ProductClientService { private final WebClient webClient; public ProductClientService(WebClient webClient) { this.webClient = webClient; } public Product getProductById(String productId) { return webClient.get() .uri(\"/products/{id}\", productId) .retrieve() .bodyToMono(Product.class) .block(); // 同步获取(可用异步处理替代) }}

OrderController.java

@RestController@RequestMapping(\"/orders\")public class OrderController { private final ProductClientService productClientService; public OrderController(ProductClientService productClientService) { this.productClientService = productClientService; } @GetMapping(\"/product/{id}\") public ResponseEntity<Product> getProductInfo(@PathVariable String id) { Product product = productClientService.getProductById(id); return ResponseEntity.ok(product); }}

3. 请求示例

启动两个服务后,访问:

GET http://localhost:8080/orders/product/101
返回 JSON(来自 Product Service):

{ \"id\": \"101\", \"name\": \"Sample Product\", \"price\": 99.99}

4. 提示:在注册中心 + 负载均衡下的用法

若使用 Eureka 注册中心,修改配置如下:

WebClientConfig.java
@Configurationpublic class WebClientConfig { @Bean @LoadBalanced // 使 WebClient 支持服务名调用 public WebClient.Builder webClientBuilder() { return WebClient.builder(); }}

使用服务名调用(不写 localhost)

webClientBuilder.build() .get() .uri(\"http://product-service/products/{id}\", productId) .retrieve() .bodyToMono(Product.class) .block();

5. 项目结构总结

order-service/├── config/│ └── WebClientConfig.java├── controller/│ └── OrderController.java├── service/│ └── ProductClientService.java└── model/ └── Product.java

热门小吃推荐