1、简介
Feign是一个声明式WebService客户端。使用Feign能让编写Web Service客户端更加简单, 它的使用方法是定义一个接口,然后在上面添加注解,同时也支持JAX-RS标准的注解。Feign也支持可拔插式的编码器和解码器。SpringCloud对Feign进行了封装,使其支持了Spring MVC标准注解和HttpMessageConverters。Feign可以与Eureka和Ribbon组合使用以支持负载均衡。
1)Feign可帮助我们更加便捷,优雅地调用HTTP API。
2)在SpringCloud中,使用Feign非常简单——创建一个接口,并在接口上添加一些注解,代码就完成了。
3)Feign支持多种注解,例如Feign自带的注解或者JAX-RS注解等。
4)SpringCloud对Feign进行了增强,使Feign支持了SpringMVC注解,并整合了Ribbon和Eureka,从而让Feign的使用更加方便。
2、实例
2.1 Feign的配置
从Spring Cloud Edgware开始,Feign支持使用属性自定义Feign。对于一个指定名称的FeignClient(例如该Feign Client的名称为 feignName ),Feign支持如下配置项:
2.2 请求压缩
Spring Cloud Feign 支持对请求和响应进行GZIP压缩,以减少通信过程中的性能损耗。通过下面的参数即可开启请求与响应的压缩功能:
同时,我们也可以对请求的数据类型,以及触发压缩的大小下限进行设置:
注:上面的数据类型、压缩大小下限均为默认值
2.3 日志级别
在开发或者运行阶段往往希望看到Feign请求过程的日志记录,默认情况下Feign的日志是没有开启的。要想用属性配置方式来达到日志效果,只需在 application.yml 中添加如下内容即可:
logging.level.xx : debug : Feign日志只会对日志级别为debug的做出响应
feign.client.config.shop-service-product.loggerLevel : 配置Feign的日志Feign有四种日志级别:1)NONE【性能最佳,适用于生产】:不记录任何日志(默认值)
2)BASIC【适用于生产环境追踪问题】:仅记录请求方法、URL、响应状态代码以及执行时间
3)HEADERS:记录BASIC级别的基础上,记录请求和响应的header。
4)FULL【比较适用于开发及测试环境定位问题】:记录请求和响应的header、body和元数据。
2.4 源码分析
通过上面的使用过程,@EnableFeignClients和@FeignClient两个注解就实现了Feign的功能,那我们从@EnableFeignClients注解开始分析Feign的源码(1)EnableFeignClients注解
通过 @EnableFeignClients 引入了FeignClientsRegistrar客户端注册类
(2)FeignClientsRegistrar注册类
通过其类结构可知,由于实现了ImportBeanDefinitionRegistrar接口,那么在registerBeanDefinitions()中就会解析和注册BeanDefinition,主要注册的对象类型有两种:
1)注册缺省配置的配置信息
2)注册那些添加了@FeignClient的类或接口 : 这也是我们讨论的重点
该方法主要是扫描类路径,对所有的FeignClient生成对应的 BeanDefinitio 。同时又调用了registerClientConfiguration 注册配置的方法,这里是第二处调用。这里主要是将扫描的目录下,每个项目的配置类加载的容器当中。调用 registerFeignClient 注册对象
(3) 注册FeignClient对象
通过分析可知:我们最终是向Spring中注册了一个bean,bean的名称就是类或接口的名称(也就是本例中的FeignService),bean的实现类是FeignClientFactoryBean,其属性设置就是我们在@FeignClient中定义的属性。那么下面我们在Controller中对FeignService的的引入,实际就是引入了FeignClientFactoryBean 类
(4) FeignClientFactoryBean类对@EnableFeignClients注解的源码进行了分析,了解到其主要作用就是把带有@FeignClient注解的类或接口用FeignClientFactoryBean类注册到Spring中。
通过 FeignClientFactoryBean 类结构可以发现其实现了FactoryBean类,那么当从ApplicationContext中获取该bean的时候,实际调用的是其getObject()方法。返回调用getTarget()方法
1)FeignClientFactoryBean实现了FactoryBean的getObject、getObjectType、isSingleton方法;实现了InitializingBean的afterPropertiesSet方法;实现了ApplicationContextAware的setApplicationContext方法
2)getObject调用的是getTarget方法,它从applicationContext取出FeignContext,然后构造Feign.Builder并设置了logger、encoder、decoder、contract,之后通过configureFeign根据FeignClientProperties来进一步配置Feign.Builder的retryer、errorDecoder、request.Options、requestInterceptors、queryMapEncoder、decode404
3)初步配置完Feign.Builder之后再判断是否需要loadBalance,如果需要则通过loadBalance方法来设置,不需要则在Client是LoadBalancerFeignClient的时候进行unwrap
(5) 发送请求由上可知,FeignClientFactoryBean.getObject()具体返回的是一个代理类,具体为FeignInvocationHandler
- FeignInvocationHandler实现了InvocationHandler,是动态代理的代理类。
- 当执行非Object方法时进入到this.dispatch.get(method)).invoke(args)
- dispatch是一个map集合,根据方法名称获取MethodHandler。具体实现类为
SynchronousMethodHandler
- SynchronousMethodHandler内部创建了一个RequestTemplate对象,是Feign中的请求模板对象。内部封装了一次请求的所有元数据。
- retryer中定义了用户的重试策略。
- 调用executeAndDecode方法通过client完成请求处理,client的实现类是LoadBalancerFeignClient
本文暂时没有评论,来添加一个吧(●'◡'●)