Feign底层原理是基于jdk动态代理实现,给被调用的目标类创建一个代理对象(FeignInvocationHandler),代理对象中维护着类中各个方法对应具体调用的Map(Map<Method, MethodHandler>),根据方法(url)获取到MethodHandler之后,由MethodHandler进行调用处理。
整体调用链如下图(来源于网络)
调用原理图如下(注册->创建->调用)
一、Feign 注册机制分析
1.1 @FeignClient 注解扫描与 Bean 注册
Feign 的注册流程起始于 @EnableFeignClients 注解,该注解通过 @Import(FeignClientsRegistrar.class) 引入了 FeignClientsRegistrar 类,负责扫描所有 @FeignClient 注解的接口并生成 Bean 定义。
核心源码分析:
流程说明:
- 类路径扫描:通过
ClassPathScanningCandidateComponentProvider扫描所有标记@FeignClient的接口。 - 生成 FactoryBean:为每个 Feign 接口生成
FeignClientFactoryBean的 Bean 定义,该 FactoryBean 负责创建 Feign 动态代理实例。 - BeanDefinition 注册:将 FactoryBean 注册到 Spring 容器,Key 为接口全限定名,Value 为代理对象。
1.2 动态代理生成
FeignClientFactoryBean 的 getObject() 方法触发代理对象的生成,核心逻辑在 Feign.Builder 中完成。
源码片段:
关键类图:
@FeignClient → FeignClientsRegistrar → FeignClientFactoryBean
→ Feign.Builder → ReflectiveFeign → Proxy
流程图:
graph TD
A[启动类EnableFeignClients] --> B[FeignClientsRegistrar]
B --> C[扫描FeignClient接口]
C --> D[注册FeignClientFactoryBean]
D --> E[Feign.Builder构建配置]
E --> F[ReflectiveFeign生成JDK Proxy]
二、Feign 调用机制分析
2.1 动态代理触发请求
当调用 Feign 接口方法时,JDK 动态代理的 InvocationHandler 实现类 ReflectiveFeign.FeignInvocationHandler 会接管请求,路由到具体的 SynchronousMethodHandler。
源码分析:
// ReflectiveFeign.FeignInvocationHandler
public Object invoke(Object proxy, Method method, Object[] args) {
// 根据方法分发到MethodHandler
return dispatch.get(method).invoke(args);
}
// SynchronousMethodHandler
public Object invoke(Object[] argv) {
// 构建RequestTemplate
RequestTemplate template = buildTemplateFromArgs.create(argv);
// 执行请求并解码响应
return executeAndDecode(template);
}
2.2 请求构造与负载均衡
RequestTemplate 构建完成后,通过 Client 实现(如 FeignBlockingLoadBalancerClient)发送请求,使用Spring Cloud LoadBalancer 实现负载均衡。
关键流程:
- 参数编码:使用
Encoder处理请求体。 - 服务发现:通过
ServiceDiscovery解析服务名到实例列表。 - 负载均衡:LoadBalancer 的 choice 选择具体实例。
- HTTP 请求:最终由 Apache HttpClient 或 OkHttp 发送请求。
时序图:
sequenceDiagram
participant Client as Feign Client
participant Handler as SynchronousMethodHandler
participant LBClient as LoadBalancerClient
participant LoadBalancer as LoadBalancer
Client ->> Handler: invoke()
Handler ->> Handler: buildTemplate()
Handler ->> LBClient: execute()
LBClient ->> LoadBalancer: chooseServer()
LoadBalancer -->> LBClient: Server
LBClient ->> HttpClient: sendRequest()
HttpClient -->> Handler: Response
Handler ->> Decoder: decode()
Decoder -->> Client: Result
2.3 核心类协作
SynchronousMethodHandler:处理方法级请求逻辑。LoadBalancerClient:使用 ReactiveLoadBalancer 根据负载均衡获取server端。RequestTemplate:定义请求参数、URL、Header 模板。
源码示例:
// LoadBalancerFeignClient
public Response execute(Request request, Request.Options options) {
ServiceInstance instance = loadBalancer.choose(serviceId);
URI originalUri = URI.create(request.url());
String reconstructedUrl = buildUrl(instance, originalUri);
Request newRequest = buildRequest(request, reconstructedUrl);
return delegate.execute(newRequest, options);
}
三、总结
- 注册阶段:通过动态代理和 Spring Bean 生命周期管理,将 Feign 接口转化为可执行的代理对象。
- 调用阶段:通过责任链模式整合参数编码、负载均衡、HTTP 请求等组件,实现声明式 HTTP 调用。
- 设计亮点:高度模块化设计(Encoder/Decoder/Client 可插拔)、与 Spring 生态无缝集成。
整体来说Feign的原理比较清晰明朗,与大多数组件一样,都是注册、实例化、调用。
扩展思考:Feign 如何与 Spring Cloud Gateway 协同?如何通过自定义 Contract 支持非 Spring 注解?