前两篇介绍了灰度方案以及灰度的实现,这篇从feign底层调用上分析一下是如何实现的。
首先,我们在feign调用时,使用了FeignClient注解。
#接口调用@FeignClient("demo-service")public interface DemoServiceFeginClient {}# 开启feign@EnableFeignClients(basePackages = {"com.yxkong.api"})public class ApiStarter {}
定位下发现注解位于
FeignClient和EnableFeignClients 位于Maven:org.springframework.cloudspring-cloud-openfeign-core2.2.8.RELEASE
我们看下EnableFeignClients的源码
//关键点,利用spring的动态注册bean的机制,public EnableFeignClients {
class FeignClientsRegistrarimplements ImportBeanDefinitionRegistrar, ResourceLoaderAware, EnvironmentAware {public void registerBeanDefinitions(AnnotationMetadata metadata,BeanDefinitionRegistry registry)//注册feign配置到registryregisterDefaultConfiguration(metadata, registry);//根据配置扫描的feignClient,生成bean并注册到registryregisterFeignClients(metadata, registry);}}
public void registerFeignClients(AnnotationMetadata metadata,BeanDefinitionRegistry registry) {//关键代码,遍历所有的clientfor (String basePackage : basePackages) {candidateComponents.addAll(scanner.findCandidateComponents(basePackage));}}
整个feign的逻辑流程如下:

这里又有两个点:
1,Client 用哪个?怎么注入的?
2,Targeter用哪个?
回过头来,继续看
<T> T getTarget() {//context 从哪里来?FeignContext context = beanFactory != null? beanFactory.getBean(FeignContext.class): applicationContext.getBean(FeignContext.class);//Feign又从哪来?Feign.Builder builder = feign(context);}

其中
Defult是feign的默认实现,内部使用HttpURLConnection 执行调用;
LoadBalancerFeignClient是在org.springframework.cloud.openfeign.ribbon包下;
剩下的两个在org.springframework.cloud.openfeign.loadbalancer 包下。
这种注入性的配置在springboot里一般都在configuration中。
看下spring.factorieswe文件
=\org.springframework.cloud.openfeign.ribbon.FeignRibbonClientAutoConfiguration,\org.springframework.cloud.openfeign.hateoas.FeignHalAutoConfiguration,\org.springframework.cloud.openfeign.FeignAutoConfiguration,\org.springframework.cloud.openfeign.encoding.FeignAcceptGzipEncodingAutoConfiguration,\org.springframework.cloud.openfeign.encoding.FeignContentGzipEncodingAutoConfiguration,\org.springframework.cloud.openfeign.loadbalancer.FeignLoadBalancerAutoConfiguration
AutoConfiguration 是有顺序的。
在FeignRibbonClientAutoConfiguration中,
//第一个就是HttpClientFeignLoadBalancedConfiguration@Import({ HttpClientFeignLoadBalancedConfiguration.class,OkHttpFeignLoadBalancedConfiguration.class,HttpClient5FeignLoadBalancedConfiguration.class,DefaultFeignLoadBalancedConfiguration.class })public class FeignRibbonClientAutoConfiguration {}
//没引入这个类,不执行//这里又导入了HttpClientclass HttpClientFeignLoadBalancedConfiguration {}//这个也没引入,不执行class OkHttpFeignLoadBalancedConfiguration {}//这个没引入,不执行class HttpClient5FeignLoadBalancedConfiguration {}
再看最后一个
(proxyBeanMethods = false)class DefaultFeignLoadBalancedConfiguration {public Client feignClient(CachingSpringLoadBalancerFactory cachingFactory,SpringClientFactory clientFactory) {return new LoadBalancerFeignClient(new Client.Default(null, null), cachingFactory,clientFactory);}}
到这,默认的Client 的注入有了。
我们再看
@Configuration(proxyBeanMethods = false)@ConditionalOnClass(Feign.class)@EnableConfigurationProperties({ FeignClientProperties.class,FeignHttpClientProperties.class, FeignEncoderProperties.class })@Import(DefaultGzipDecoderConfiguration.class)public class FeignAutoConfiguration {@Configuration(proxyBeanMethods = false)@Conditional(DefaultFeignTargeterConditions.class)protected static class DefaultFeignTargeterConfiguration {@Bean@ConditionalOnMissingBeanpublic Targeter feignTargeter() {return new DefaultTargeter();}}@Configuration(proxyBeanMethods = false)@Conditional(FeignCircuitBreakerDisabledConditions.class)@ConditionalOnClass(name = "feign.hystrix.HystrixFeign")//优先使用这个@ConditionalOnProperty(value = "feign.hystrix.enabled", havingValue = "true",matchIfMissing = true)protected static class HystrixFeignTargeterConfiguration {@Bean@ConditionalOnMissingBeanpublic Targeter feignTargeter() {return new HystrixTargeter();}}@Configuration(proxyBeanMethods = false)@ConditionalOnClass(CircuitBreaker.class)@ConditionalOnProperty(value = "feign.circuitbreaker.enabled", havingValue = "true")protected static class CircuitBreakerPresentFeignTargeterConfiguration {@Bean@ConditionalOnMissingBean@ConditionalOnBean(CircuitBreakerFactory.class)public Targeter circuitBreakerFeignTargeter(CircuitBreakerFactory circuitBreakerFactory) {return new FeignCircuitBreakerTargeter(circuitBreakerFactory);}}}
到这,默认的Targeter 是 HystrixTargeter。
到此feign初始化的流程分析完了。
下篇接着分析路由。
原文作者:5ycode;如有侵权,请联系管理员删除。