在Spring Cloud体系中,Feign是封装了底层的HttpClient组件来做的一次远程的接口调用,类似于调本地方法一样,主要通过EnableFeignClients注解开启改功能的。
该类通过@Import注解注入FeignClientsRegistrar.class到Spring的Bean工厂,主要是是带@FeignClient注解的类以BeanDefinitiond注册到BeanDefinitionRegistry中去。
首先是解析EnableFeignClients注解属性配置, 如果配置了clients属性,就增加一个TypeFilter过滤器加入Scanner,然后通过ClassPathScanningCandidateComponnetProvider这个类扫描含有FeignClient注解的类,
解析到EnableFeignClients中scanPackage属性值,进行的FeignClient注解类的扫描了。这里看到FeignClient只能扫描的是接口类型的类。
下面是注册FeignClient的BeanDefinition到BeanDefinitionRegistry的逻辑,这里注册的类是FeignClientFactoryBean类,它是实现FactoryBean接口的,它实际构造的Bean是getObject返回的对象
FeignClientFactoryBean是实现FactoryBean接口,BeanFactory调用getBean的时候,最终是通过FactoryBean的getObject获取的实际的对象。这也是FactoryBean接口和普通的Bean初始化的区别。
其中获取FeignClient的Bean会调用FeignClientFactoryBean的getObject的方法获取实际的Bean对象。
这里就一个方法getTarget是创建FeignClientl类型的Bean的方法。这里可以看到FeignClient可以配置URL(相当于直接连接IP), 如果没有配置url参数,则直接创建loadbalance方法创建的Targeter对象。
feign方法主要是利用builder模式,设置编码器和解码器以及支持的契约(Contract), 其中 Contract支持默认的契约,JAXRS2契约以及SpringMvc契约。
从FeignContext中获取的Client的bean,实际创建的bean是LoadBalanceFeignClient, 这里是负载均衡的客户端调用的。
上面的Targeter对象是实际对象是HystrixTargeter,调用target生成代理对象,这里是默认Feign的Builder。
这里Feign的builder内部类,创建ReflectiveFeign的类,并调用newInstance方法,创建代理对象。
这里build是创建ReflectiveFeignHandler对象,调用newInstance方法,创建动态代理对象,这里可以看出是使用JDK的动态代理生成的Proxy,
JDK的动态代理会调用实现的InvocationHandler的nvoke方法,通过缓存Method和MethodHandler,实现MethodHandler的分发调用,
最终通过Method签名获取MethodHandler处理编码,并发起HTTP请求,然后获取结果并解码结果等操作。这里的MathodHandler实际是想是SynchronousMethodHandler。而且它的executeAndDecode方法就是执行的发起HTTP请求的地方。
Client实际对象是LoadBalancerFeignClient 执行execute发起Http请求调用.
Feign的客户端通过注册中心 执行执行负载均衡策略的操作,然后执行HTTP请求。
总结
今天主要梳理了下,Spring Cloud的Feign的通过JDK的接口的动态代理执行了HTTP请求,并解响应的流程。有不明白的地方,多多指教。