0%

Feign的执行流程

Feign 执行流程:从接口定义到请求响应的全链路解析

Feign 作为声明式 HTTP 客户端,其执行流程围绕 “接口代理→请求构建→发送→响应处理” 展开,核心依赖动态代理和组件协作(如编码器、解码器、负载均衡等)。以下是 Feign 执行的完整流程解析:

启动初始化阶段:Feign 客户端的注册

Feign 的执行从应用启动开始,核心是通过@EnableFeignClients注解触发 Feign 客户端的扫描与注册。

1. 开启 Feign 功能

@EnableFeignClients注解通过@Import(FeignClientsRegistrar.class)导入注册器,触发 Feign 客户端的扫描:

1
2
3
4
5
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(FeignClientsRegistrar.class) // 关键:导入注册器
public @interface EnableFeignClients { ... }

2. 扫描并注册 Feign 客户端

FeignClientsRegistrar的核心逻辑:

  • 扫描标注@FeignClient的接口(如DeptClient);
  • 为每个接口创建动态代理工厂Feign.Builder),并将代理对象注册到 Spring 容器中;
  • 代理对象的核心处理器为SynchronousMethodHandler(负责后续方法调用的拦截与处理)。

此时,Spring 容器中已存在 Feign 接口的代理 Bean,等待被调用。

方法调用阶段:动态代理与请求构建

当业务代码调用 Feign 接口的方法(如deptClient.get(1L))时,动态代理开始工作,触发请求构建流程。

1. 动态代理拦截调用

Feign 为每个@FeignClient接口生成动态代理对象,代理的核心逻辑在SynchronousMethodHandlerinvoke方法中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// SynchronousMethodHandler.invoke():拦截方法调用
public Object invoke(Object[] argv) throws Throwable {
// 1. 根据方法参数构建RequestTemplate(请求模板)
RequestTemplate template = buildTemplateFromArgs.create(argv);
// 2. 获取请求配置(如超时时间)
Options options = findOptions(argv);
// 3. 初始化重试器
Retryer retryer = this.retryer.clone();
// 4. 执行请求(带重试逻辑)
while (true) {
try {
return executeAndDecode(template, options); // 核心:执行并解码响应
} catch (RetryableException e) {
// 重试逻辑:根据异常判断是否重试
retryer.continueOrPropagate(e);
continue;
}
}
}

2. 构建 RequestTemplate(请求模板)

buildTemplateFromArgs.create(argv)是请求构建的核心,负责将方法参数转换为 HTTP 请求的基本信息(URL、参数、请求体等):

  • 参数解析:根据接口方法的注解(如@GetMapping("/dept/get/{id}")@PathVariable)解析 URL 路径、请求方法(GET/POST);

  • 请求体编码:若参数含@RequestBody,通过Encoder(编码器)将对象序列化为 JSON/XML 等格式(如SpringEncoder使用 Jackson 序列化):

    1
    2
    // BuildEncodedTemplateFromArgs(参数编码逻辑)
    encoder.encode(body, metadata.bodyType(), mutable); // 序列化请求体
  • 构建模板:最终生成RequestTemplate,包含完整的请求信息(URL、方法、 headers、body 等)。

请求发送阶段:Client 与负载均衡

RequestTemplate构建完成后,Feign 通过Client接口发送 HTTP 请求,同时集成负载均衡(如 Ribbon)选择服务实例。

1. 生成 HTTP Request 对象

RequestTemplate通过request()方法转换为Request对象(Feign 定义的 HTTP 请求实体),包含最终的 URL、请求体字节数组等。

2. Client 发送请求

Feign 的Client接口负责实际发送请求,默认实现为:

  • Default:基于 JDK 原生HttpURLConnection(无连接池,性能较差);
  • 可替换为ApacheHttpClientOkHttpClient(需引入对应依赖,支持连接池)。

发送请求的入口在executeAndDecode方法中:

1
2
3
4
5
6
7
// executeAndDecode():发送请求并处理响应
Response response;
try {
response = client.execute(request, options); // Client发送请求
} catch (IOException e) {
throw errorExecuting(request, e); // 处理IO异常(如连接失败)
}

3. 负载均衡集成

在 Spring Cloud 中,Client会被LoadBalancedRetryFeignClientFeignLoadBalancer包装,集成 Ribbon 实现负载均衡:

  • 根据@FeignClient(name = "SPRINGCLOUD2-PROVIDER")中的服务名,从服务注册中心(如 Nacos、Eureka)获取可用实例列表;
  • 通过负载均衡策略(如轮询、随机)选择一个实例,替换 URL 中的服务名为具体 IP: 端口;
  • 发送请求到选中的实例。

响应处理阶段:解码与结果返回

请求发送后,Feign 对响应进行解码、异常处理,最终将结果返回给调用者。

1. 响应解码

executeAndDecode方法中,通过Decoder(解码器)将 HTTP 响应体转换为接口方法的返回类型(如CommonResult<Dept>):

1
2
3
4
5
// 响应解码逻辑
if (response.status() >= 200 && response.status() < 300) {
Object result = decode(response); // 调用Decoder解码
return result;
}
  • SpringDecoder是默认解码器,基于 Spring 的HttpMessageConverter(如 Jackson 反序列化 JSON);
  • 若返回类型为Response,则直接返回原始响应体。

2. 异常处理

  • HTTP 错误状态(如 404、500):通过ErrorDecoder解析为FeignException(可自定义异常类型);
  • 重试机制:若异常为RetryableException(如超时、503 服务不可用),触发Retryer重试(默认不重试,可通过Retryer.Default配置重试策略);
  • 熔断降级:若配置了fallbackFactory,当请求失败时,通过工厂类创建降级实例,并捕获异常原因(如超时、连接拒绝)。

3. 结果返回

解码后的结果(如CommonResult<Dept>)被返回给业务代码,完成一次 Feign 调用。

核心组件协作流程图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
业务代码调用Feign接口方法

动态代理(SynchronousMethodHandler.invoke())

构建RequestTemplate(参数解析+编码器编码)

生成HTTP Request对象

Client发送请求(集成负载均衡选择服务实例)

接收HTTP Response响应

解码器(Decoder)解析响应体

返回结果给业务代码
(异常时触发重试/熔断降级)

总结

Feign 的执行流程本质是 “动态代理驱动的组件协作”:

  • 启动阶段通过@EnableFeignClients注册代理 Bean;
  • 调用阶段通过动态代理构建请求(依赖编码器)、发送请求(依赖 Client 和负载均衡);
  • 响应阶段通过解码器解析结果,并处理异常(重试、降级)

欢迎关注我的其它发布渠道

表情 | 预览
快来做第一个评论的人吧~
Powered By Valine
v1.3.10