Feign系列文章(二)Feign 源码原理深度解析:从接口到 HTTP 请求的全过程

共计 2002 个字符,预计需要花费 6 分钟才能阅读完成。

一、前言

在上一篇文章中,我们介绍了 Feign 的基本用法、优势和实践。本篇文章将带你深入源码,了解 Feign 是如何将一个 Java 接口转换成实际的 HTTP 请求。

二、总体调用流程图

Feign系列文章(二)Feign 源码原理深度解析:从接口到 HTTP 请求的全过程

三、@FeignClient 背后发生了什么?

1. @EnableFeignClients 启动

在 Spring Boot 启动时,@EnableFeignClients 会触发 FeignClientsRegistrar 的调用,扫描定义了 @FeignClient 注解的接口,并注册到 Spring 容器中,内部通过 FeignClientFactoryBean 以 FactoryBean 方式创建实例。

2. FeignClientFactoryBean 创建代理

@Override
public Object getObject() throws Exception {
    return getTarget();
}

<T> T getTarget() {
    FeignContext context = this.applicationContext.getBean(FeignContext.class);
    Builder builder = feign(context); // 构造 Feign.Builder
    Targeter targeter = get(context, Targeter.class);
    return targeter.target(this, builder, context); // 调用 target() 创建代理对象
}

四、Feign 代理对象是怎么实现的?

Feign 基于 Java JDK 动态代理把接口转换成代理对象,每次调用方法时会触发 InvocationHandler#invoke(),而实现是 ReflectiveFeign.FeignInvocationHandler

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    MethodHandler handler = dispatch.get(method);
    return handler.invoke(args); // 调用 SynchronousMethodHandler
}

五、SynchronousMethodHandler 调用逻辑

SynchronousMethodHandler 是 Feign 中大部分请求逻辑的核心实现:

@Override
public Object invoke(Object[] argv) throws Throwable {
    RequestTemplate template = buildTemplateFromArgs.create(argv); // 生成请求模板
    Request request = targetRequest(template);
    Response response = client.execute(request, options); // HTTP 请求
    return decode(response); // 转换为实体类
}
  • buildTemplateFromArgs 根据方法参数 + 注解 生成 RequestTemplate
  • client.execute() 是给定的第三方 HTTP Client (default: Apache HttpClient)
  • decode(response) 通过 Decoder 解析返回值

六、其他扩展和配置点

1. Client

可自定义 Client Bean,支持 OkHttp, Apache HttpClient 或自定义实现:

@Bean
public Client feignClient() {
    return new OkHttpClient();
}

2. Contract

默认使用 SpringMvcContract,支持 @RequestMapping/ @GetMapping/ @RequestBody 等 Spring MVC 注解解析

3. Encoder / Decoder

支持 JSON / XML / Protobuf 等编解码,可自定义:

@Bean
public Decoder feignDecoder() {
    return new JacksonDecoder();
}

4. Retryer

支持重试策略,可配置 Retryer 实现

5. 日志 Logger

高级日志输出,方便调试 HTTP 请求详情

七、总结

本文展示了 Feign 的调用全过程:

  1. 接口注解 @FeignClient 被扫描 -> 注册 FactoryBean
  2. FactoryBean 调用 target() -> 构造代理对象
  3. 代理调用 -> 引入 MethodHandler#invoke
  4. SynchronousMethodHandler 构造请求 -> HTTP Client 发送 -> Decoder 转换

Feign 为什么能这么简洁?源因就是这套经过精密设计的调用链路和动态代理机制。


如果本文对你有帮助,欢迎点赞、评论!我是 李卷卷,专注Java相关知识输出。感谢阅读!

正文完
 0
admin
版权声明:本站原创文章,由 admin 于2025-05-19发表,共计2002字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
评论(没有评论)