OpenFeign源码剖析
feign的核心功能就是通过接口去访问网络资源,里面也是用动态代理来实现的,就跟Mybatis用接口去访问数据库一样,我们就来看下源码的处理,核心就一个包:
1.1 注解处理
使用OpenFeign的时候会用到2个注解,分别是@FeignClient(value = "hailtaxi-driver")
和@EnableFeignClients(basePackages = "com.itheima.driver.feign")
,这两个注解其实就是学习OpenFeign的入口。
@EnableFeignClients
这 个注解的作用其实就是开启了一个FeignClient
的扫描,那么点击启动类的@EnableFeignClients
注解看下他是怎么开启FeignClient
的扫描的,进去后发现里面有个@Import(FeignClientsRegistrar.class)这个FeignClientsRegistrar跟Bean的动态装载有关。
FeignClientsRegistrar类中有一个方法registerBeanDefinitions
用于注入Bean的,源码如下:
我们主要关注registerFeignClients()
方法,该方法会通过解析@EnableFeignClients
并解析@FeignClient
实现Feign的注册,源码如下:
上面注解解析后,会调用registerFeignClient()
注册客户端,我们来看下registerFeignClient()
方法具体实现流程,代码如下:
1.2 Feign代理注册
上面方法中创建BeanDefinitionBuilder
的时候传入了一个参数FeignClientFactoryBean.class
,注册的Bean就是参数中自己传进来的beanClass是工厂Bean,可以用来创建Feign的代理对象,我们来看一下FeignClientFactoryBean
源码,可以发现它实现了FactoryBean,所以它可以获取对象实例,同时也能创建对象的代理对象,部分源码如下:
它里面有一个方法getObject()
,该方法就是用于返回一个对象实例,而对象其实是代理对象,源码如下:
1.3 Builder对象
上面片段代码中Feign.Builder builder = feign(context)
是用于构建Builder,关于Builder源码属性我们进行详细讲解,源码如下:
builder构建如下方法:
1.4 Feign代理创建
上面的builder构造完后继续向下走,配置完Feign.Builder之后,再判断是否需要LoadBalance,如果需要,则通过loadBalance(builder, context,new HardCodedTarget<>(this.type, this.name, this.url));的方法来设置。实际上他们最终调用的是Target.target()方法。
上面方法会调用targeter.target(this, builder, context, target);
,它支持服务熔断降级,我们直接看默认的DefaultTrageter
就可以了。DefaultTargeter
的target()
方法是一个非常简单的调用,但开启了Feign代理对象创建的开始:target
方法调用了build().newInstance(),这个方法信息量比较大,我们要拆分这看build()
和newInstance(target)
:
build()方法是创建客户端对象ReflectiveFeign
,看着名字就像代理的意思,源码如下:
我们再来看ReflectiveFeign
,它继承了Feign
同时也有一个属性InvocationHandlerFactory
,该对象其实就是代理工厂对象,源码如下:
ReflectiveFeign
源码:InvocationHandlerFactory
源码:
我们再来看newInstance(Target<T> target)
方法,该方法就是用来创建Feign的代理对象,源码如下:
1.5 远程请求
远程请求一定是要有IP和端口的,OpenFeign将IP和端口封装到RequestTemplate中了,我们来看一下RequestTemplate源码:
在SynchronousMethodHandler
类中执行远程调用,源码如下:
上面调用会调用executeAndDecode()
方法,该方法是执行远程请求,同时解析响应数据,源码如下: