基于springcloud的灰度实现方案-feign调用
Posted 鱼翔空
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了基于springcloud的灰度实现方案-feign调用相关的知识,希望对你有一定的参考价值。
前两篇介绍了灰度方案以及灰度的实现,这篇从feign底层调用上分析一下是如何实现的。
首先,我们在feign调用时,使用了FeignClient注解。
#接口调用
@FeignClient("demo-service")
public interface DemoServiceFeginClient {
}
# 开启feign
@EnableFeignClients(basePackages = {"com.yxkong.api"})
public class ApiStarter {
}
定位下发现注解位于
FeignClient和EnableFeignClients 位于
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 ImportBeanDefinitionRegistrar, ResourceLoaderAware, EnvironmentAware {
@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初始化的流程分析完了。
下篇接着分析路由。
如果觉得对你有帮助,请关注公众号:5ycode,后续会不断更新哦
以上是关于基于springcloud的灰度实现方案-feign调用的主要内容,如果未能解决你的问题,请参考以下文章
SpringCloud实战(十七)-基于Ribbon动态路由实现:调用链控制/版本控制/灰度发布(粒度更细,可以控制到每一个微服务模块版本的路由)
SpringCloud实战(十七)-基于Ribbon动态路由实现:调用链控制/版本控制/灰度发布(粒度更细,可以控制到每一个微服务模块版本的路由)