5ycode
被管理耽误的架构师。工作、学习过程中的知识总结与分享,jvm,多线程,架构设计,经验分享等。
公众号
前两篇介绍了灰度方案以及灰度的实现,这篇从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的源码
//关键点,利用spring的动态注册bean的机制,
public EnableFeignClients {
class FeignClientsRegistrar
implements ImportBeanDefinitionRegistrar, ResourceLoaderAware, EnvironmentAware {
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.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 {
}
//没引入这个类,不执行
//这里又导入了HttpClient
class HttpClientFeignLoadBalancedConfiguration {
}
//这个也没引入,不执行
class OkHttpFeignLoadBalancedConfiguration {
}
//这个没引入,不执行
class HttpClient5FeignLoadBalancedConfiguration {
}
再看最后一个
false) (proxyBeanMethods =
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
@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初始化的流程分析完了。
下篇接着分析路由。
文章评论