聊聊Feign的大致功能和代理类的构建
聊聊Feign的大致功能和代理类的构建
Feign相当于RestTemplate+Ribbon+Hystrix,Feign本身集成了Ribbon的依赖和自动装配,Feign的默认的请求超时时长是1秒,我们可以通过配置Ribbon的参数来调整请求处理超时时长,ReadTimeout参数就是请求处理超时时长,单位是毫秒
当服务超时的时候,Ribbon会将请求转移给其他服务,我们可以配置MaxAutoRetries参数来确定当下实例重试次数,第一次调用不算,配置MaxAutoRetriesNextServer参数来调整切换到其他实例的重试次数
配置日志
Feign还支持日志的配置:
@Configuration
public class FeignLogConfiguration {
@Bean
Logger.Level feignLog() {
return Logger.Level.FULL;
}
}
然后在Feign的客户端配置文件中添加具体feign接口的日志为debug
logging:
level:
FeignInterface: debug
Feign也支持熔断,可以通过配置开启熔断,然后使用@FeignClient的fallback属性来配置回退方法,可以设置Hystrix的超时时间
当配置了Ribbon的超时时间和Hystrix的超时时间,处理时长超过两个中的最短时长就会回退降级,Feign还支持请求和响应的压缩,来提升请求的性能
feign的本质
Feign的本质是通过FeignInvocationHandler来增强代理发送请求
那么FeignInvocationHandler是怎么生成的呢,我们先从它的注解@EnableFeignClients开启Feign的注解开始分析,注解中导入了FeignClientsRegistrar类,FeignClientsRegistrar实现了ImportBeanDefinitionRegistrar接口,重写registerBeanDefinitions()方法来注册Bean实例
registerBeanDefinitions()方法中
- registerDefaultConfiguration()是FeignClient的全局配置注入到容器中,就是取@EnableFeignClients注解中的配置
- registerFeignClients()方法把被@FeignClient注解修饰的类注入到容器中:定义扫描器扫描basePackage下的被@FeignClient注解修饰的类
我们使用的其实是FeignClientFactoryBean的getObject()方法返回的对象
看一下FeignClientFactoryBean的getObject()方法:
首先会获得Feign.Builder构建器,如果没有配置了url就进行,也就是说有的服务名,这时候就需要进行负载均衡的了:
loadBalance()方法中获取LoadBalancerFeignClient,然后使用Builder来包装这个LoadBalancerFeignClient,最终会调用ReflectiveFeign的newInstance()方法来获取实例,这里使用JDK的动态代理,生成了FeignInvocationHandler的代理类
FeignInvocationHandler的invoke()方法中调用方法对应的MethodHandler的invoke()方法,以SynchronousMethodHandler为例,
SynchronousMethodHandler的invoke()方法中:
- 构建RestTemplate对象
- 调用executeAndDecode(template)方法来执行请求和解码
在executeAndDecode()方法中使用LoadBalancerFeignClient来执行请求,
-
LoadBalancerFeignClient的execute()方法中构建Ribbon请求来调用AbstractLoadBalancerAwareClient的executeWithLoadBalancer()方法
-
这里方法里又调用LoadBalancerCommand的submit()方法
-
LoadBalancerCommand的submit()方法中调用selectServer()方法来选择合适的服务,然后使用call()方法发起调用,最终是使用HttpURLConnection来发起请求的
Client接口的内部类Default的execute()方法:
-
-
@Override
public Response execute(Request request, Options options) throws IOException {
HttpURLConnection connection = convertAndSend(request, options);
return convertResponse(connection).toBuilder().request(request).build();
}
- 我们看一下selectServer()方法,方法中调用getServerFromLoadBalancer(),在getServerFromLoadBalancer()方法里构建ILoadBalancer的实现类正是Ribbon中用的ZoneAwareLoadBalancer,使用调用chooseServer()方法,这些就是Ribbon中的内容了
总结
今天我们说了一下Feign的工作原理,发起请求的时候是通过一个FeignInvocationHandler的代理类来执行的,我们基于源码分析了代理类是怎么起作用的,发起请求的时候并且用到了Ribbon的选择服务然后负载均衡的功能,Feign与Ribbon实现了结合
- 点赞
- 收藏
- 关注作者
评论(0)