type
status
date
slug
summary
tags
category
icon
password
1、Feign核心架构和原理
Feign 调用的核心原理:通过一系列的封装和注解,讲
@FeignClient
注解修饰的接口方法,转换成调用远程服务的 HTTP 请求,经过均衡负载器的处理将请求发送给远程服务,并解析请求结果返回给调用者,调用者在调用远程服务的方法的时候感觉就跟调用本地方法一样透明。借助网上的一张图解释这个流程:

2、Feign调用的流程
2.1 Feign调用的初始化过程
2.1.1 注解驱动机制
Feign的启动始于
@EnableFeignClients
注解,该注解一般放在启动类上,通过FeignClientsRegistrar
类实现接口扫描和动态代理创建:FeignClientsRegistrar
实现了ImportBeanDefinitionRegistrar
接口,在registerBeanDefinitions
方法中完成:- 扫描所有被
@FeignClient
标记的接口
- 为每个接口创建
FeignClientFactoryBean
工厂Bean
- 注册 BeanDefinition 到 Spring 容器
2.1.2 代理对象创建流程
当 Spring 容器初始化 Feign客户端时,会调用
FeignClientFactoryBean.getObject()
方法,核心代码如下:最终会调用
ReflectiveFeign.newInstance()
方法创建 JDK 动态代理对象2.2 动态代理与调用拦截机制
2.2.1 代理类生成
ReflectiveFeign.newInstance()
方法核心逻辑:这里创建的
InvocationHandler
实例,是 Feign 自己基于 java.lang.reflect
包中的 InvocationHandler
接口实现的代理类 FeignInvocationHandler
,这个代理类是 ReflectiveFeign
的内部类。这个内部类的两个核心关注点:
dispatch
属性:是一个Map<Method, MethodHandler>
,存储了每个方法对应的处理器。
invoke
方法:选择方法对应的处理器执行方法。
2.2.2 方法调用拦截
当调用 Feign 接口方法时,会进入
FeignInvocationHandler.invoke()
方法,这里会选择方法对应的 MethodHandler
的 invoke
方法,完成实际的 HTTP 请求和结果的处理。MethodHandler
是 Feign 定义的独立的接口,定义在 InvocationHandlerFactory
接口中,仅仅拥有一个 invoke
方法。MethodHandler
的invoke 方法,主要职责是完成实际远程URL请求,然后返回解码后的远程 URL 的响应结果。Feign 提供了默认的 SynchronousMethodHandler
实现类,提供了基本的远程 URL 的同步请求处理。
2.3 请求构建与执行流程
2.3.1 请求模板构建
SynchronousMethodHandler.invoke()
是实际处理HTTP请求的核心:SynchronousMethodHandler
的 invoke
方法,调用了自己的 executeAndDecode
请求执行和结果解码方法。该方法的工作步骤:- 首先通 RequestTemplate 请求模板实例,生成远程 URL 请求实例 request;
- 然后用自己的 feign 客户端 client 属性,
excecute
执行请求,并且获取 response 响应;
- 对 response 响应进行结果解码。
这里的 client 属性,基于 Feign 自定义的
Client
接口,这是 Feign 中一个非常重要的组件,负责端到端的执行 URL 请求。2.3.2 HTTP客户端执行
Client
接口是客户端的顶层接口支持多种 HTTP 客户端实现:
Client.Default
:默认的feign.Client
客户端实现类,内部使用HttpURLConnnection
完成 URL 请求处理。
ApacheHttpClient
:基于 Apache HttpClient 开源组件的的 feign.Client 客户端实现类,需要另外引入feign-httpclient
依赖。
OkHttpClient
:基于 OkHttp3 开源组件的 feign.Client 客户端实现类,需要另外引入feign-okhttp
依赖。
FeignBlockingLoadBalancerClient
:基于 LoadBalancer 负载均衡的 feign.Client 客户端实现类,通过LoadBalancerClient
选择服务实例,重构请求 URL 后委托给底层 HTTP 客户端(如 Apache HttpClient 或 OkHttp)执行请求。
在 Spring Cloud 环境中,默认使用
FeignBlockingLoadBalancerClient
实现负载均衡。2.3.2 请求拦截器处理
请求会经过一系列拦截器处理,拦截器的顶层接口是
RequestInterceptor
。内置拦截器包括:
BasicAuthRequestInterceptor
:处理基础认证
FeignAcceptGzipEncodingInterceptor
:处理编码类型
FeignContextGzipEncodingInterceptor
:处理内容压缩
2.4 均衡负载处理
均衡负载器的顶级接口是
LoadBalancerClient
,这里面最重要的是 choose
方法和 execute
方法。LoadBalancerClient
接口的默认实现类是 BlockingLoadBalancerClient
,这一个同步/阻塞式的客户端均衡负载实现。他的作用有:- 服务实例选择:根据服务ID从注册中心获取可用实例列表
- 负载均衡策略:应用配置的负载均衡算法(如轮询、随机等),默认为轮询(实现类为
RoundRobinLoadBalancer
)
- 服务调用:自动将
@FeignClient
的服务名解析为实际地址。
2.5 调用流程时序图
写一个最简单的远程调用例子,消费者控制器
ConsumerController
@FeignClient
注解修饰的接口生产者控制器
ProviderController
当调用
ConsumerController.helloFeign()
方法时,整个流程时序图如下所示:
3、性能优化建议
1、使用连接池
使用 Apache HttpClient 或 OkHttp 替换默认的 HttpURLConnection。以 Apache HttpClient 为例:
第一步,引入依赖
第二步,启用配置,在 application.yml 中配置:
第三步,自定义配置
2、合理配置超时
3、启用压缩:
4、缓存设计:对不变的结果进行适当缓存
5、日志优化:合理设置日志级别避免性能损耗
- Author:mcbilla
- URL:http://mcbilla.com/article/1dc85c7d-7c1d-808f-aed9-dc5c58b2942f
- Copyright:All articles in this blog, except for special statements, adopt BY-NC-SA agreement. Please indicate the source!