基于springcloud的灰度实现方案(三)-feign调用

2021/05/20 1582点热度 1人点赞 0条评论

5ycode
5ycode

被管理耽误的架构师。工作、学习过程中的知识总结与分享,jvm,多线程,架构设计,经验分享等。
28篇原创内容

公众号

基于springcloud的灰度实现方案(一)

基于springcloud的灰度实现方案(二)

前两篇介绍了灰度方案以及灰度的实现,这篇从feign底层调用上分析一下是如何实现的。

首先,我们在feign调用时,使用了FeignClient注解。

#接口调用@FeignClient("demo-service")public interface DemoServiceFeginClient {}# 开启feign@EnableFeignClients(basePackages = {"com.yxkong.api"})public class ApiStarter {}

定位下发现注解位于

FeignClientEnableFeignClients  位于Maven:     org.springframework.cloud    spring-cloud-openfeign-core    2.2.8.RELEASE

我们看下EnableFeignClients的源码

@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.TYPE)@Documented//关键点,利用spring的动态注册bean的机制,@Import(FeignClientsRegistrar.class)public @interface EnableFeignClients {
class FeignClientsRegistrar    implements ImportBeanDefinitionRegistrarResourceLoaderAwareEnvironmentAware {  @Override  public void registerBeanDefinitions(AnnotationMetadata metadata,      BeanDefinitionRegistry registry)     //注册feign配置到registry    registerDefaultConfiguration(metadata, registry);    //根据配置扫描的feignClient,生成bean并注册到registry        registerFeignClients(metadata, registry);  }    }

  public void registerFeignClients(AnnotationMetadata metadata,      BeanDefinitionRegistry registry) {    //关键代码,遍历所有的client    for (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.boot.autoconfigure.EnableAutoConfiguration=\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 {}
@Configuration(proxyBeanMethods = false)//没引入这个类,不执行@ConditionalOnClass(ApacheHttpClient.class)@ConditionalOnProperty(value = "feign.httpclient.enabled", matchIfMissing = true)@Conditional(HttpClient5DisabledConditions.class)//这里又导入了HttpClient@Import(HttpClientFeignConfiguration.class)class HttpClientFeignLoadBalancedConfiguration {}@Configuration(proxyBeanMethods = false)//这个也没引入,不执行@ConditionalOnClass(OkHttpClient.class)@ConditionalOnProperty("feign.okhttp.enabled")@Import(OkHttpFeignConfiguration.class)class OkHttpFeignLoadBalancedConfiguration {}@Configuration(proxyBeanMethods = false)//这个没引入,不执行@ConditionalOnClass(ApacheHttp5Client.class)@ConditionalOnProperty(value = "feign.httpclient.hc5.enabled", havingValue = "true")@Import(HttpClient5FeignConfiguration.class)class HttpClient5FeignLoadBalancedConfiguration {}

再看最后一个

@Configuration(proxyBeanMethods = false)class DefaultFeignLoadBalancedConfiguration {
@Bean @ConditionalOnMissingBean 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 @ConditionalOnMissingBean public 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 @ConditionalOnMissingBean public 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初始化的流程分析完了。

下篇接着分析路由。

yxkong

这个人很懒,什么都没留下

文章评论