一、Feign 是什么?
Feign 是 Spring Cloud 提供的一个声明式 HTTP 客户端,用来简化微服务之间的远程调用。
- 你只需要写一个接口,加几个注解,就能像调用本地方法一样调用远程服务
- 它内部已经集成了 Ribbon,自带负载均衡能力
核心优势
代码极度简洁:不用手动拼接 URL、不用自己写 HTTP 请求
自带负载均衡:和 Ribbon 无缝集成,支持轮询、随机等策略
支持 Spring MVC 注解:@RequestMapping、@RequestParam、@PathVariable 等都能用
Feign 与 Ribbon / 负载均衡的关系
Feign 内部默认集成了 Ribbon,自带负载均衡能力
你不需要手动给 RestTemplate 加 @LoadBalanced,Feign 已经帮你做好了
默认负载均衡策略是轮询,也可以自定义策略:
二,使用feign
创建文件 四个工程

创建接口

feign_consumer
在启动类 添加 EnableFeignClients 注解 扫描 Feign的注解 @FeignClient("feign-provider")

@Autowired
private UserFeign userFeign; 只需要这一个就行

在启动
在访问 consumer的 路径就会跳转 common1和common2 的内容了
三,feign的原理
1、@EnableFeignClients开启feign注解的支持:FeignClientsRegistrar.registerFeignClients():扫描被@FeignClient标识的接口并生成代理类交给spring容器管理
2、为接口方法创建requestTemplate:当consumer调用feign的代理类时,代理类会调用SynchronousMethodHandler.invoke()创建requestTemplate
四、feign的传参方式
1、?传参
@RequestParam("sb"):url?sb=250
2、restful传参
@PathVariable("sb"):url/{sb}--->url/250
3、pojo传参
@RequestBody:pojo--->json
feign_consumer
java
package com.yunkukukukuku.controller;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/consumer")
public class ConsumerController {
@Autowired
private UserFeign userFeign; // Feign 客户端
//获取用户信息 {} 传参
@RequestMapping("/getUserById/{id}")
public User getUserById(@PathVariable Integer id) {
// 调用 Feign 客户端的方法获取用户信息
return userFeign.getUserById(id);
}
//restful 传参
@RequestMapping("/getUserById2")
public User getUserById2( User user) {
return userFeign.getUserById2(user);
}
//? 传参
@RequestMapping("/getUserById3")
public User getUserById3(@RequestParam("id") Integer id) {
// 调用 Feign 客户端的方法获取用户信息
return userFeign.getUserById3(id);
}
//pojo 传参
@RequestMapping("/getUserById4")
public List<User> getUserById4() {
List<User> userList = new ArrayList<>();
-----
return userFeign.getUserById4(userList);
}
}
feign_interface
java
package com.yunkukukukuku;
import java.util.List;
@FeignClient("feign-provider")
@RequestMapping("/provider")
public interface UserFeign {
//获取用户信息 {} 传参
@RequestMapping("/getUserById/{id}")
public User getUserById(@PathVariable("id") Integer id);//PathVariable 获取路径中的参数
//restful
@RequestMapping("/getUserById2")
User getUserById2( @RequestBody User user);//RequestBody 获取请求体中的参数
//? 传参
@RequestMapping("/getUserById3")
User getUserById3(@RequestParam("id") Integer id);//RequestParam 获取路径中的参数
//pojo 传参
@RequestMapping("/getUserById4")
List<User> getUserById4(List<User> userList);
}
feign_provider_1 controller
java
package com.yunkukukukuku.controller;
import java.util.List;
@RestController
@RequestMapping("/provider")
public class ProviderController {
@Autowired
private UserService userService;
@RequestMapping("/getUserById/{id}")
public User getUserById(@PathVariable Integer id) {
return userService.getUserById(id);
}
//restful
@RequestMapping("/getUserById2")
public User getUserById2(@RequestBody User user) {
return userService.getUserById2(user);
}
//? 传参
@RequestMapping("/getUserById3")
User getUserById3(@RequestParam("id") Integer id) {
return userService.getUserById3(id);
}
//pojo 传参
@RequestMapping("/getUserById4")
public List<User> getUserById4(List<User> userList) {
return userService.getUserById4(userList);
}
}
五,补充
坑 1:对象参数传参报错(你之前的 IllegalStateException)
-
问题:Feign 默认会把对象参数当成
@RequestBody处理,而你的 Provider 端是用 URL 查询参数接收 -
解决:Feign 接口的对象参数上必须加
@SpringQueryMap,让它自动把对象展开成?id=12&name=xxx格式的 URL 参数
坑 2:@PathVariable 不加参数名报错
-
问题:Feign 接口中
@PathVariable("id")必须指定参数名,否则无法绑定路径变量 -
解决:必须写
@PathVariable("id"),不能省略"id"
坑 3:@RequestParam 必须指定参数名
-
问题:Feign 接口中
@RequestParam("id")必须指定参数名,否则会报错 -
解决:必须写
@RequestParam("id"),不能省略"id"
| 场景 | 注解 | 适用请求方式 | 备注 |
|---|---|---|---|
| 路径变量 | @PathVariable |
GET | 路径中必须有 {变量名} |
| URL 查询参数(单个) | @RequestParam |
GET/POST | 必须指定参数名 |
| URL 查询参数(对象) | @SpringQueryMap |
GET/POST | 必须加此注解 |
| 请求体 JSON | @RequestBody |
POST/PUT | 只能用 POST/PUT,不能用 GET |