OpenFeign的服务调用原理

OpenFeign主要用于微服务项目中的服务远程调用,它有两个核心注解@FeignClient@EnableFeignClients,以下将从这两个注解着手,通过分析源码,看看OpenFeign是怎样与Spring整合的,以及OpenFeign到底做了什么。

一、@EnableFeignClients开启openfeign

@EnableFeignCleints是加在启动类上的,当程序启动后,会按照basepackage进行包扫描,扫描所有被@FeignCleint注解修饰的接口,通过JDK动态代理来创建代理对象,并注册到Spring容器中。

1、进入@EnableFeignClients注解,其中引入了FeignClientsRegistrar类,进入该类中的registerBeanDefinitions()方法,里面有以下两个方法。

1、registerDefaultConfiguration方法将会读取@EnableFeignClients接口的属性,如果存在自定义配置类那么就会被注册到容器中。

2、registerFeignClients则会扫描所有注解了@FeignClient的接口,然后像spring本地Bean一样地注册到容器中。

重点看registerFeignClients()方法,该方法主要是扫描basepackage下的所有@FeignClient注解的接口,然后把所有包含@FeignClient注解的接口都注册到spring的beanfactory去,让开发人员可以@Autowired来调用。

 2、进入registerFeignClient()方法,该方法根据读取的@FeignClient注解的属性配置,以及该接口的类名信息,把扫描出来的BeanDefinition变成 FeignClientFactoryBean 类注入到Spring容器。

这里值得注意的是genericBeanDefinition方法最终生成的其实是FeignClientFactoryBean,注进容器的也是FeignClientFactoryBean,而FeignClientFactoryBean向上直接实现了FactoryBean接口。

在spring中,FactoryBean是一个工厂bean,用于创建代理bean,也就是说,spring将会通过调用FeignClientFactoryBean的getObject来获取@FeignClient注解的接口对应的Bean对象。

总之,openfeign的自动配置过程逻辑相对比较简单,就是扫描了一下@FeignClient注解的接口,然后将根据BeanDefinition生成的FeignClientFactoryBean注入到容器当中。而具体的Bean对象,将会通过调用FeignClientFactoryBean的getObject方法来获取。

二、代理对象proxy的生成

@FeignClient注解的接口被扫描到以后,会生成一个FeignClientFactoryBean。然后,spring将会通过调用FeignClientFactoryBean的getObject方法来获取@FeignClient注解的接口对应的代理对象。

 1、进入FeignClientFactoryBean类,找到getObject()方法,里面返回的是当前的被@FeignClient注解那个接口的类名。

2、Feign是怎么拿到注册中心的服务地址的呢?进入getTarget()方法,获取了一个上下文以及Feign的构造器,FeignContext是在FeignAutoConfiguration被解析的时候成为Bean的。

如果服务提供方已经注册到注册中心了,那么@FeignClient注解上的name或者value的值就是服务提供方的服务名称。假设我们配置的name为service-provider-product,那么url就是:http://service-provider-product。

3、进入loadBalance()方法,获取代理对象的实现由Targeter的实现类处理,默认是HystrixTargeter。

 4、进入HystrixTargeter类,找到target方法,这里将会回调feign的构造代理对象的过程方法

 5、进入feign.target()方法,build将会构造出Feign对象,而newInstance会返回代理对象

 6、进入ReflectiveFeign类,找到newInstance()方法,在这里,Feign接口的代理对象就被创建出来了,在使用接口过程实际调用的这是这个代理对象的InvocationHandler.invoke()方法。

 代理对象的构建主要有以下内容

1、为了创建Feign的远程接口的代理对象,Feign提供了自己的一个默认的调用处理器FeignInvocationHandler(如果Feign与Hystrix结合使用,则会替换成 HystrixInvocationHandler 调用处理器类)

2、jdk动态代理需要提供InvocationHandler,而FeignInvocationHandler将由InvocationHandlerFactory的create方法实现。

3、通过Proxy.newProxyInstance方法,生成proxy对象。

同样在ReflectiveFeign类中找到内部FeignInvocationHandler类,里面有一个非常重要Map类型成员 dispatch 映射,保存着远程接口方法到MethodHandler方法处理器的映射。

调用proxy对象发起http请求

在这里插入图片描述

  1、jdk的动态代理将会调用FeignInvocationHandler的invoke方法,那么FeignInvocationHandler是怎么调用Method的?

 FeignInvocationHandle在处理远程方法调用的时候,会根据Java反射的方法实例,在dispatch 映射对象中找到对应的MethodHandler 方法处理器,然后交给MethodHandler 完成实际的HTTP请求和结果的处理。

2、Feign的方法处理器 MethodHandler 是一个独立的接口,定义在 InvocationHandlerFactory 接口中,仅仅拥有一个invoke()方法,主要职责是完成实际远程URL请求,然后返回解码后的远程URL的响应结果。

  3、MethodHandler的默认实现类是SynchronousMethodHandler,进入其invoke方法,executeAndDecode将会负责发起http请求。

 executeAndDecode()方法的作用如下:

  • 首先通过 RequestTemplate 请求模板实例,生成远程URL请求实例 request;
  • 然后用自己的 feign 客户端client成员,excecute() 执行请求,并且获取 response 响应;
  • 对response 响应进行结果解码。

4、Feign的客户端组件负责端到端的执行URL请求,其核心的逻辑:发送request请求到服务器,并接收response响应结果并进行解码。进入Client接口中,找到execute()方法。

 feign.Client 有以下多个不同的实现:

(1)Client.Default类:默认的feign.Client 客户端实现类,内部使用HttpURLConnnection 完成URL请求处理;

(2)ApacheHttpClient 类:内部使用 Apache httpclient 开源组件完成URL请求处理的feign.Client 客户端实现类;

(3)OkHttpClient类:内部使用 OkHttp3 开源组件完成URL请求处理的feign.Client 客户端实现类。

(4)LoadBalancerFeignClient 类:内部使用 Ribben 负载均衡技术完成URL请求处理的feign.Client 客户端实现类。

openFeign生成@FeignClient注解的接口的代理对象是从FeignClientFactoryBean的getObject方法开始的,生成proxy对象主要由ReflectiveFeign对象来实现。调用proxy对象,其实就是发起http请求,请求结果将被解码并返回。所以,正如Feign本身的意义一样,http远程调用被伪装成了本地调用一样简单的代理对象,对于使用者来说就是调用本地接口一样简单。

Feign的工作流程总结如下:

  1. 主程序启动扫描@EnableFeignClients注解,根据basepackage扫描所有@FeignCleint注解的接口,生成FeignClientFactoryBean,通过getObject方法来获取@FeignClient注解的接口对应的代理对象,注入Spring容器。
  2. Feign默认的调用处理器FeignInvocationHandler内部保持了一个远程调用方法实例和方法处理器的一个Key-Value键值对Map映射。在其invoke()方法中,会根据Java反射的方法实例,在dispatch 映射对象中找到对应的 MethodHandler 方法处理器,然后由后者完成实际的HTTP请求和结果的处理。
  3. Feign默认的方法处理器为 SynchronousMethodHandler,其invoke()方法主要是通过内部成员feign客户端成员client,完成远程URL请求执行和获取远程结果。feign.Client 客户端有多种类型(HttpClient、OkHttp、HttpURLConnection),不同的类型完成URL请求处理的具体方式不同。

事实上,SynchronousMethodHandler 并不是直接完成远程URL的请求,而是通过负载均衡机制,定位到合适的远程server 服务器,然后再完成真正的远程URL请求。换句话说,SynchronousMethodHandler实例的client成员,其实是 LoadBalancerFeignClient 客户端负载均衡类型。 因此,上面的第3步可以进一步细分(1)首先通过 SynchronousMethodHandler 内部的client实例,实质为负责客户端负载均衡 LoadBalancerFeignClient 实例,首先查找到远程的 server 服务端;(2)然后再由LoadBalancerFeignClient 实例内部包装的feign.Client.Default 内部类实例,去请求server端服务器,完成URL请求处理。

简单点来说:OpenFeign是springcloud在Feign的基础上支持了SpringMVC的注解,如@RequestMapping等等。OpenFeign的@FeignClient可以解析SpringMVC的@RequestMapping注解下的接口,并通过动态代理的方式产生实现类,实现类中做负载均衡并调用其他服务。

  • 6
    点赞
  • 36
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
OpenFeign是一个用于微服务项目中的服务远程调用的工具,它与Spring整合通过两个核心注解@FeignClient和@EnableFeignClients来实现。@EnableFeignClients注解用于开启OpenFeign,在启动类上添加该注解后,Spring容器将会扫描被@FeignClient注解修饰的接口,并生成相应的代理对象。 生成@FeignClient注解接口的代理对象是从FeignClientFactoryBean的getObject方法开始的。具体而言,代理对象的生成主要由ReflectiveFeign对象来实现。调用代理对象实际上就是发起http请求,请求结果会被解码并返回。因此,OpenFeign将http远程调用伪装成了本地调用,对于使用者来说,调用远程接口就像调用本地接口一样简单。 总结一下OpenFeign的工作流程:首先,通过@EnableFeignClients注解开启OpenFeign;然后,OpenFeign扫描被@FeignClient修饰的接口;接下来,根据被修饰的接口生成相应的代理对象;最后,使用代理对象发起http请求,并将请求结果解码返回给调用者。 因此,OpenFeign远程调用原理可以概括为通过代理对象将远程调用转化为http请求,并将请求结果解码返回给调用者。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [OpenFeign服务调用原理](https://blog.csdn.net/qq_42098875/article/details/118994449)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值