Spring Boot Feign 接口 vs HTTP 接口 — 完整学习笔记
2026/6/26 6:42:06 网站建设 项目流程

目录

  1. 基础概念
  2. HTTP 接口(RestController)底层原理
  3. Feign 接口底层原理
  4. 两者架构对比
  5. Feign 核心组件详解
  6. Header 与上下文传递
  7. 负载均衡与服务发现
  8. 熔断与降级
  9. 优缺点对比
  10. 常见问题与踩坑
  11. 本项目实践总结

1. 基础概念

1.1 HTTP 接口(@RestController)

外部客户端(浏览器、App、其他服务)通过 HTTP 协议直接调用,由 Spring MVC 处理。

外部调用方 │ HTTP Request(含 Header:userId、orgId 等) ▼ Servlet Filter(如 UserFilter)→ 填充 UserContext ▼ DispatcherServlet → HandlerMapping → Controller 方法 ▼ 返回 JSON 响应

1.2 Feign 接口

微服务之间内部调用的方式。调用方像调本地方法一样调用,底层由 Feign 框架转成 HTTP 请求发出去。

服务 A(调用方) │ 调用 Java 接口方法(如 searchDocsFacade.searchCenterDocs(param)) ▼ Feign 动态代理(拦截方法调用) │ 构造 HTTP Request(序列化参数、拼接路径) │ RequestInterceptor(注入 Header) ▼ 负载均衡(Ribbon / LoadBalancer)→ 选一个服务实例 ▼ HTTP 请求发出 → 服务 B(被调方,如 bm-search) ▼ 服务 B 的 Filter → Controller/FacadeImpl 处理 ▼ HTTP 响应 → Feign 反序列化 → 返回 Java 对象给调用方

2. HTTP 接口(RestController)底层原理

2.1 整体请求处理链

HTTP Request │ ▼ Tomcat(Servlet 容器) │ 接收请求,封装为 HttpServletRequest ▼ FilterChain(责任链模式) │ UserFilter、CorsFilter、AuthFilter 等依次执行 ▼ DispatcherServlet(前端控制器,Spring MVC 核心) │ ├─ HandlerMapping:根据路径找到 Controller 方法(HandlerMethod) ├─ HandlerAdapter:调用方法前处理参数绑定 │ ├─ @RequestBody → HttpMessageConverter(如 Jackson)反序列化 JSON │ ├─ @PathVariable / @RequestParam → 从 URL 提取 │ └─ @RequestHeader → 从 Header 提取 ├─ Controller 方法执行 └─ HandlerAdapter:处理返回值 └─ @ResponseBody → HttpMessageConverter 序列化为 JSON │ ▼ HTTP Response

2.2 关键类

职责
DispatcherServletSpring MVC 入口,统一调度
RequestMappingHandlerMapping维护 URL → HandlerMethod 的映射表
RequestMappingHandlerAdapter处理参数绑定、执行方法、处理返回值
HttpMessageConverterJava 对象 ↔ JSON/XML 互转(Jackson)
OncePerRequestFilter每次请求只执行一次的过滤器基类(UserFilter 继承它)

2.3 UserFilter 在本项目的作用

// UserFilter 拦截 /v1/search/* 路径// 从 Header 读取 userId、orgId 写入 ThreadLocal(UserContext)// 请求结束后 finally 块清理,防止线程复用时的数据污染USER_CONTEXT.put(UserContext.USER_ID,userId);// ...filterChain.doFilter(request,response);// ...USER_CONTEXT.remove(UserContext.USER_ID);// finally 块

3. Feign 接口底层原理

3.1 动态代理机制

Feign 的核心是JDK 动态代理。启动时扫描@FeignClient注解的接口,为每个接口生成代理类。

// 你注入的其实不是 SearchDocsFacade 的实现类// 而是 Feign 生成的代理对象@AutowiredprivateSearchDocsFacadesearchDocsFacade;// → 实际是 HardCodedTarget$FeignInvocationHandler// 调用方法时触发 InvocationHandler.invoke()searchDocsFacade.searchCenterDocs(param);// ↓// ReflectiveFeign.FeignInvocationHandler.invoke()// ↓// SynchronousMethodHandler.invoke() → 真正构造并发送请求

3.2 请求构造过程(SynchronousMethodHandler)

SynchronousMethodHandler.invoke(args) │ ├─ 1. RequestTemplate 构造 │ 读取接口方法上的 @PostMapping、@RequestBody 等注解 │ 将方法参数序列化填入 body / path / query │ ├─ 2. RequestInterceptor 执行(可扩展点) │ 遍历所有注册的 RequestInterceptor.apply(template) │ → 可在此注入 userId、orgId 等 Header │ ├─ 3. 编码(Encoder) │ 将 RequestBody 对象序列化为 JSON 字节流 │ 默认使用 SpringEncoder(内部用 Jackson) │ ├─ 4. 负载均衡(LoadBalancerFeignClient) │ 将 http://bm-search/v1/search/docs 中的服务名 │ 替换为真实 IP:Port(如 http://192.168.1.10:8080/v1/search/docs) │ ├─ 5. 发送 HTTP 请求(OkHttpClient / HttpURLConnection) │ ├─ 6. 解码(Decoder) │ 将响应 JSON 反序列化为 Result<?> 对象 │ └─ 7. 错误处理(ErrorDecoder) 非 2xx 响应 → 抛出 FeignException 或自定义异常

3.3 @FeignClient 注解解析

@FeignClient(name="bm-search",// 服务名,用于从注册中心查找实例contextId="searchDocsFacade",// 同一服务多个 FeignClient 时区分 Bean 名称url

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询