OpenFeign 声明式服务调用
5.1 OpenFeign 是什么?
OpenFeign 是声明式 HTTP 客户端。
它让我们像调用本地 Java 接口一样调用远程服务。
不用自己手写:
java
RestTemplate
WebClient
HttpClient
OkHttp而是声明接口:
java
@FeignClient("stock-service")
public interface StockClient {
@PostMapping("/stock/reduce")
String reduce(@RequestParam("productId") Long productId,
@RequestParam("count") Integer count);
}然后直接注入使用:
java
stockClient.reduce(1001L, 2);5.2 OpenFeign 调用原理
核心流程:
text
启动时扫描 @FeignClient
↓
为接口生成代理对象
↓
调用接口方法
↓
根据注解拼接 HTTP 请求
↓
通过服务名找注册中心实例
↓
负载均衡选择一个服务实例
↓
发送 HTTP 请求
↓
解析响应结果5.3 OpenFeign 依赖
在 order-service 中引入:
xml
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>还需要服务发现:
xml
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>5.4 开启 Feign
在 order-service 启动类上添加:
java
package com.demo.order;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;
@EnableFeignClients
@SpringBootApplication
public class OrderServiceApplication {
public static void main(String[] args) {
SpringApplication.run(OrderServiceApplication.class, args);
}
}5.5 编写 Feign 接口
java
package com.demo.order.client;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.*;
@FeignClient(name = "stock-service")
public interface StockClient {
@GetMapping("/stock/info")
String info();
@PostMapping("/stock/reduce")
String reduce(@RequestParam("productId") Long productId,
@RequestParam("count") Integer count);
}5.6 order-service 调用 stock-service
java
package com.demo.order.controller;
import com.demo.order.client.StockClient;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/order")
public class OrderController {
private final StockClient stockClient;
public OrderController(StockClient stockClient) {
this.stockClient = stockClient;
}
@GetMapping("/create")
public String createOrder(@RequestParam("productId") Long productId,
@RequestParam("count") Integer count) {
String stockResult = stockClient.reduce(productId, count);
return "创建订单成功,库存服务返回:" + stockResult;
}
}访问:
text
http://localhost:8081/order/create?productId=1001&count=25.7 Feign 常见参数传递
5.7.1 Query 参数
服务提供者:
java
@GetMapping("/stock/query")
public String query(@RequestParam("productId") Long productId) {
return "productId=" + productId;
}Feign:
java
@GetMapping("/stock/query")
String query(@RequestParam("productId") Long productId);5.7.2 PathVariable 参数
服务提供者:
java
@GetMapping("/stock/{productId}")
public String getById(@PathVariable("productId") Long productId) {
return "productId=" + productId;
}Feign:
java
@GetMapping("/stock/{productId}")
String getById(@PathVariable("productId") Long productId);5.7.3 JSON Body 参数
DTO:
java
package com.demo.api.dto;
public class StockReduceRequest {
private Long productId;
private Integer count;
public Long getProductId() {
return productId;
}
public StockReduceRequest setProductId(Long productId) {
this.productId = productId;
return this;
}
public Integer getCount() {
return count;
}
public StockReduceRequest setCount(Integer count) {
this.count = count;
return this;
}
}服务提供者:
java
@PostMapping("/stock/reduce-json")
public String reduceJson(@RequestBody StockReduceRequest request) {
return "扣减库存成功,productId=" + request.getProductId()
+ ", count=" + request.getCount();
}Feign:
java
@PostMapping("/stock/reduce-json")
String reduceJson(@RequestBody StockReduceRequest request);5.8 Feign 超时时间配置
yaml
spring:
cloud:
openfeign:
client:
config:
default:
connectTimeout: 3000
readTimeout: 5000解释:
text
connectTimeout:连接超时时间
readTimeout:读取响应超时时间也可以针对某个服务配置:
yaml
spring:
cloud:
openfeign:
client:
config:
stock-service:
connectTimeout: 1000
readTimeout: 20005.9 Feign 日志配置
配置日志级别:
yaml
logging:
level:
com.demo.order.client: DEBUG
spring:
cloud:
openfeign:
client:
config:
default:
loggerLevel: FULL常见日志级别:
text
NONE:不记录日志
BASIC:只记录请求方法、URL、响应状态码、执行时间
HEADERS:记录 BASIC + 请求响应头
FULL:记录请求响应头、Body、元数据5.10 Feign 常见坑
坑 1:忘记加 @EnableFeignClients
现象:
text
No qualifying bean of type 'xxxClient'解决:
java
@EnableFeignClients坑 2:Feign 接口路径和服务端路径不一致
现象:
text
404 Not Found解决:
text
检查 @GetMapping、@PostMapping、@RequestMapping 路径。坑 3:RequestParam 忘记写 value
建议始终写完整:
java
@RequestParam("productId") Long productId不要写成:
java
@RequestParam Long productId坑 4:服务名写错
java
@FeignClient(name = "stock-service")要和 Nacos 注册中心中的服务名一致:
yaml
spring:
application:
name: stock-service