1. 背景知识
梳理SpringMVC和Feign客户端常用注解后,本文对两类注解做个对比。
理解两者定位(服务端 vs 客户端)是掌握注解使用的关键:
- Spring MVC注解用于服务端,描述如何解析一个HTTP请求;
- Feign客户端注解用于客户端,描述如何构造一个HTTP请求(包括URL、参数、头、体等)
2.功能定位对比
| 特性 | Spring MVC 注解 | Feign客户端 注解 |
|---|---|---|
| 定位方向 | 服务端(接收请求) | 客户端(发送请求) |
| 主要功能 | 处理传入的 HTTP 请求; 路由请求、解析请求参数、处理请求体、渲染响应等。 | 构建对外的 HTTP 请求; 将 Java 接口转化为 HTTP 请求,发送到远程服务端。 |
| 运行位置 | 服务提供方 | 服务消费方 |
| 典型场景 | 暴露 REST API | 调用其他服务的 REST API |
3.核心注解对比
3.1 请求映射
| 功能 | Spring MVC注解 | Feign客户端注解 |
|---|---|---|
| 类级别映射 |
| @FeignClient |
| 方法级别映射 | @GetMapping/@PostMapping 等 | @GetMapping/@PostMapping 等 |
| 绑定路径变量 | @PathVariable | @PathVariable(必须显式命名) |
3.2 参数处理
| 参数类型 | Spring MVC(获取) | Feign客户端(设置) |
|---|---|---|
| 绑定查询参数 | 自动绑定 POJO 或 @RequestParam | @RequestParam 或 @SpringQueryMap |
| 绑定请求体 | @RequestBody | @RequestBody |
| 绑定请求头 | @RequestHeader(获取请求头) | @RequestHeader(在客户端设置请求头发送给服务端) |
| 表单数据 | @ModelAttribute | 需自定义编码器 |
| 文件上传 | @RequestPart | @RequestPart(需配置编码器) |
3.3 特殊功能
| 功能 | Spring MVC | Feign客户端 |
|---|---|---|
| 声明 | / | @FeignClient(Feign特有,声明一个Feign客户端) |
| 对象转查询参数 | 自动绑定 POJO | @SpringQueryMap(Feign特有,用于GET请求传递对象参数) |
| 错误处理 | @ExceptionHandler | ErrorDecoder 实现 |
| 熔断降级 | 无原生支持(需整合) | fallback/fallbackFactory(Feign特有) |
| 请求拦截 | HandlerInterceptor | RequestInterceptor |
| 配置方式 | @ControllerAdvice | @EnableFeignClients |
4. 关键差异演示
4.1. URL路径差异
//Spring MVC:
@RestController
@RequestMapping("/users")
public class UserController {
@GetMapping("/{id}")
public User getUser(@PathVariable Long id) { ... }
}
//Feign接口中必须指定完整路径(包括类上的路径),因为Feign不支持类级别的路径继承
@FeignClient(name = "user-service")
public interface UserClient {
@GetMapping("/users/{id}") // 这里必须写完整路径,包括类上没有公共前缀
User getUser(@PathVariable("id") Long id);
}
4.2. 参数处理差异
//Spring MVC 注解用于获取参数(如使用@RequestHeader获取请求头)
@PostMapping("/users")
public User createUser(@RequestBody User user,@RequestHeader("X-Token") String token)
{...}
// Feign注解用于设置参数(如使用@RequestHeader设置请求头)
@FeignClient(name="user-service")
public interface UserClient {
@PostMapping("/users")
User createUser(@RequestBody User user,@RequestHeader("X-Token") String token);
}
4.3. 路径变量处理差异
// Spring MVC(支持隐式绑定)
@GetMapping("/orders/{orderId}/items/{itemId}")
public Item getItem(@PathVariable Long orderId,
@PathVariable String itemId) {...}
// OpenFeign(@PathVariable 必须显式命名)
@FeignClient(name="order-service")
public interface OrderClient {
@GetMapping("/orders/{orderId}/items/{itemId}")
Item getItem(@PathVariable("orderId") Long orderId,
@PathVariable("itemId") String itemId);
}
4.4. 查询参数处理差异
// Spring MVC(自动绑定POJO)
@GetMapping("/search")
public List<User> searchUsers(UserQuery query) {
// 自动处理 ?name=xxx&age=xxx 到query的映射
}
// OpenFeign(需要@SpringQueryMap注解)
@FeignClient(name="user-service")
public interface UserClient {
@GetMapping("/search")
List<User> searchUsers(@SpringQueryMap UserQuery query);
//需要使用@SpringQueryMap注解构建query到 ?name=xxx&age=xxx 的映射
}
5. 二者协作演示
服务A:使用Spring MVC暴露API,服务端
// 服务A(使用Spring MVC暴露API,服务端)
@RestController
@RequestMapping("/products")
public class ProductController {
@GetMapping("/{id}")
public Product getProduct(@PathVariable Long id) {
// 返回产品信息
}
@GetMapping("/search")
public List<Product> searchProducts(ProductQuery query) {
// 返回产品列表信息
}
}
服务B:使用OpenFeign调用服务A, 客户端
// 服务B(使用OpenFeign调用服务A, 客户端)
@FeignClient(name = "product-service", configuration = FeignConfig.class)
public interface ProductClient {
@GetMapping("/products/{id}")
Product getProduct(@PathVariable("id") Long id);
@PostMapping("/products/search")
List<Product> searchProducts(@SpringQueryMap ProductQuery query);
}
// 配置类
@Configuration
public class FeignConfig {
// OpenFeign使用的拦截器为 RequestInterceptor
@Bean
public RequestInterceptor authInterceptor() {
return template -> template.header("X-Auth", "token123");
}
}
// 调用示例
@Service
public class OrderService {
private final ProductClient productClient;
public Product getProductForOrder(Long productId) {
return productClient.getProduct(productId);
}
}
6.相关阅读
- Spring MVC中常用注解_笔记
- Spring Cloud OpenFeign 常用注解_笔记
- Spring MVC拦截器:HandlerInterceptor介绍-笔记
- OpenFeign拦截器:feign.RequestInterceptor 简介-笔记

364

被折叠的 条评论
为什么被折叠?



