深入理解SpringCloud源码探究篇 | Feign源码分析

发布于:2021-12-01 14:21:13

SpringCloud系列:


    SpringCloud入门必看例子深入理解SpringCloud源码探究篇 | Eureka服务端源码分析深入理解SpringCloud源码探究篇 | Eureka客户端源码分析深入理解SpringCloud源码探究篇 | ribbon源码分析深入理解SpringCloud源码探究篇 | Feign源码分析

按照惯例先来白话文描述下Feign的工作原理



@EnableFeignClients入口,Import了FeignClientsRegistrar进行bean注册,其实际就是筛选出所有@FeignClient注解的接口,为其注册为FeignClientFactoryBean,以及注册配置FeignClientSpecification用于放不同服务名的配置信息类。FeignClientFactoryBean自然是实现类FactoryBean,返回的是getObject代理类,也就是在调用Feign接口时其实际是调用代理对象的ReflectiveFeign.FeignInvocationHandler.invoke,默认调用到SynchronousMethodHandler.invoke,这里面就会调用到Client.execute。LoadBalancerFeignClient实现了Client也就实现execute方法,这里将会进行进行调用ILoadBalancer的chooseServer方法进行以上的服务筛选获取一个服务(也就是利用到了ribbon)。接着就是发起http请求进行具体服务调用了。



?feign的自动配置类FeignRibbonClientAutoConfiguration




具体配置哪些我就不再一一展开了,其中包括LoadBalancerFeignClient,Options,FeignContext,Targeter等bean的注册


?


@EnableFeignClients注解与@FeignClient


使用feign首先是在我们的项目启动类中使用@EnableFeignClients注解进行启动扫描feign接口,同时也在feign接口中采用@FeignClient注解。这里先来看看@EnableFeignClients注解:



从该注解中我们可以看到利用@Import进行引入FeignClientsRegistrar类:



?从以上代码中可以看到FeignClientsRegistrar实现了ImportBeanDefinitionRegistrar类,该类用于bean的注册使用,实现方法registerBeanDefinitions,这里registerBeanDefinitions方法调用了:


registerDefaultConfiguration(metadata, registry);
registerFeignClients(metadata, registry);

registerDefaultConfiguration方法:?



获取EnableFeignClients注解上的信息默认配置,然后将其信息调用registerClientConfiguration进行注册:



将配置信息放入FeignClientSpecification。


回到上面registerFeignClients方法:



?从以上方法内的代码可以分析出,扫描获取@EnableFeignClients上的信息,以及扫描过滤出包下的所有@FeignClient注解的类。接着进行配置信息的注册以及feign接口的代理类注册:



先是通过getClientName获取FeignClient注解上所写的名字:



然后接着调用registerClientConfiguration方法进行将FeignClient注解上的configuration配置的配置类进行注册交由spring容器,和前面提到的EnableFeignClients默认配置defaultConfiguration一致,注册为FeignClientSpecification,这个会在FeignAutoConfiguration主动配置类中进行注入获取,然后将其配置放入到FeignContext中交由spring容器



接着调用registerFeignClient进行代理类的生成:



从以上我们可以看到将其feign接口注册为FeignClientFactoryBean,而FeignClientFactoryBean实现了FactoryBean:



所以feign接口所拿到的代理实现类是getTarget所返回的对象:



以上可以看出继续调用loadBalance:



?这里在FeignContext拿到LoadBalancerFeignClient,以及Targeter,这些都是自动配置类注册进的bean,然后接着调用到Targeter.target,这里的层次比较多就不一一截图了,最终被返回出来的是这个代理对象(该方法在ReflectiveFeign类下的newInstance):



?到这里feign接口的代理对象就被创建出来了,在使用接口过程实际调用的这是这个代理对象的InvocationHandler.invoke()


?


Feign与Ribbon结合使用


调用Feign时最终执行到的是默认SynchronousMethodHandler.invoke()



这里进到方法后创建RequestTemplate接着调用到executeAndDecode(),该方法会进行以下下操作:


response = client.execute(request, options);

?


LoadBalancerFeignClient实现类Client,这里直接看?LoadBalancerFeignClient的excute方法:



lbClient创建出FeignLoadBalancer,继承关系:



然后执行executeWithLoadBalancer(方法在父类AbstractLoadBalancerAwareClient中):



接着跟进到LoadBalancerCommand的submit:



直接先跟进查看selectServer()方法是如何进行挑选服务的:



?继续跟进:



从以上代码截图中可以看出,最终利用ILoadBalancer来调用其chooseServer方法来挑选出服务,该方法在前面深入理解SpringCloud源码探究篇 | ribbon源码分析该章提及过,最终获取到Server然后进行回调外面传入的operation.call方法(回到前面的AbstractLoadBalancerAwareClient.executeWithLoadBalancer方法):



这就完成了feign与ribbon的结合。


?


?总结


feign接口被初始为一个代理对象,调用时其实际是通过一个代理对象进行调用,最终调用到的是SynchronousMethodHandler.invoke(),利用ILoadBalancer来调用其chooseServer方法来挑选出服务,最后发起切确服务的reuqest请求,这样就完成了feign与ribbon的结合使用

相关推荐

最新更新

猜你喜欢