聊聊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()方法:

扫描二维码关注公众号,回复: 15164804 查看本文章

首先会获得Feign.Builder构建器,如果没有配置了url就进行,也就是说有的服务名,这时候就需要进行负载均衡的了:

loadBalance()方法中获取LoadBalancerFeignClient,然后使用Builder来包装这个LoadBalancerFeignClient,最终会调用ReflectiveFeign的newInstance()方法来获取实例,这里使用JDK的动态代理,生成了FeignInvocationHandler的代理类

FeignInvocationHandler的invoke()方法中调用方法对应的MethodHandler的invoke()方法,以SynchronousMethodHandler为例,

SynchronousMethodHandler的invoke()方法中:

  1. 构建RestTemplate对象
  2. 调用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实现了结合

猜你喜欢

转载自blog.csdn.net/Chenhui98/article/details/126828880