Feign 核心原理分析:注册与调用机制源码解析

476 阅读2分钟

Feign底层原理是基于jdk动态代理实现,给被调用的目标类创建一个代理对象(FeignInvocationHandler),代理对象中维护着类中各个方法对应具体调用的Map(Map<Method, MethodHandler>),根据方法(url)获取到MethodHandler之后,由MethodHandler进行调用处理。

整体调用链如下图(来源于网络) 调用原理流程

调用原理图如下(注册->创建->调用) image.png

一、Feign 注册机制分析

1.1 @FeignClient 注解扫描与 Bean 注册

Feign 的注册流程起始于 @EnableFeignClients 注解,该注解通过 @Import(FeignClientsRegistrar.class) 引入了 FeignClientsRegistrar 类,负责扫描所有 @FeignClient 注解的接口并生成 Bean 定义。

核心源码分析

image.png

image.png

流程说明

  1. 类路径扫描:通过 ClassPathScanningCandidateComponentProvider 扫描所有标记 @FeignClient 的接口。
  2. 生成 FactoryBean:为每个 Feign 接口生成 FeignClientFactoryBean 的 Bean 定义,该 FactoryBean 负责创建 Feign 动态代理实例。
  3. BeanDefinition 注册:将 FactoryBean 注册到 Spring 容器,Key 为接口全限定名,Value 为代理对象。
1.2 动态代理生成

FeignClientFactoryBeangetObject() 方法触发代理对象的生成,核心逻辑在 Feign.Builder 中完成。

源码片段

image.png

image.png

image.png

关键类图

@FeignClientFeignClientsRegistrarFeignClientFactoryBeanFeign.BuilderReflectiveFeignProxy

流程图

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 实现负载均衡。

关键流程

  1. 参数编码:使用 Encoder 处理请求体。
  2. 服务发现:通过 ServiceDiscovery 解析服务名到实例列表。
  3. 负载均衡:LoadBalancer 的 choice 选择具体实例。
  4. HTTP 请求:最终由 Apache HttpClient 或 OkHttp 发送请求。

image.png

时序图

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 注解?