springcloud feign原始碼分析(6)——關鍵元件!找一找Feign.Client用的是誰以及居然在這裡就跟ribbon關聯了!
分析完了底層的原始碼,就是用各種預設的bean、配置的bean、配置的引數,構造了一個Feign.Builder,接下來就是基於這個Feign.Builder,還得在這個Builder裡放一個Feign.Client進去。。。
如果你在@FeignClient上,沒有配置url屬性,也就是你沒有自己指定服務的url地址,那麼就會自動跟ribbon關聯起來,採用ribbon來進行負載均衡,直接就開始為ribbon來準備對應的url地址了:http://ServiceA
你在這裡,看原始碼,就可以看到@FeignClient註解的path屬性是怎麼用的
如果你要訪問的是這個ServiceA服務的某一類介面,@FeignClient(value = “ServiceA”, path = “/user”),跟你拼接請求URL地址的時候,就會拼接成:http://ServiceA/user
呼叫了loadbalance()方法,猜測一下,這個loadBalance()方法是幹嘛的??用了ribbon的支援負載均衡的這麼一個東西,可能就是一個基於ribbon進行負載均衡的動態代理
https://github.com/OpenFeign/feign
先是構造了一個HardCodedTarget,硬編碼的Target,裡面包含了介面型別(com.zhss.service.ServiceAClient)、服務名稱(ServiceA)、url地址(http://ServiceA),跟Feign.Builder、FeignContext,一起,傳入了loadBalance()方法裡去
@Data @EqualsAndHashCode(callSuper = false) class FeignClientFactoryBean implements FactoryBean<Object>, InitializingBean, ApplicationContextAware { public Object getObject() throws Exception { //構造了一個HardCodedTarget,硬編碼的Target, // 裡面包含了介面型別(com.zhss.service.ServiceAClient)、服務名稱(ServiceA)、url地址(http://ServiceA), // 跟Feign.Builder、FeignContext,一起,傳入了loadBalance()方法裡去 //用了ribbon的支援負載均衡的這麼一個東西,可能就是一個基於ribbon進行負載均衡的動態代理 return loadBalance(builder, context, new HardCodedTarget<>(this.type, this.name, url)); } protected <T> T loadBalance(Feign.Builder builder, FeignContext context, HardCodedTarget<T> target) { Client client = getOptional(context, Client.class); if (client != null) { builder.client(client); Targeter targeter = get(context, Targeter.class); return targeter.target(this, builder, context, target); } throw new IllegalStateException( "No Feign Client for loadBalancing defined. Did you forget to include spring-cloud-starter-ribbon?"); } }
Feign.Client,從FeignContext裡面獲取Feign.Client
@Data @EqualsAndHashCode(callSuper = false) class FeignClientFactoryBean implements FactoryBean<Object>, InitializingBean, ApplicationContextAware { public Object getObject() throws Exception { //DefaultFeignLoadBalancedConfiguration.class,預設的是這裡返回的Feign.Client Client client = getOptional(context, Client.class); } protected <T> T getOptional(FeignContext context, Class<T> type) { return context.getInstance(this.name, type); } }
Feign.Client,從FeignContext裡面獲取Feign.Client,如何獲取呢?預設定義的在哪兒呢?你如果在FeignAutoConfiguration、FeignClientsConfiguration中去找,Feign.Client,是沒有的。。。屁股來想想,這邊Feign一定是跟ribbon整合起來使用的,那麼我們是不是應該到feign和ribbon相關的包下面去找找?
org.springframework.cloud.netflix.feign.ribbon
這個包,一看就是feign和ribbon關聯起來的,有關係的東西都在這裡
FeignRibbonClientAutoConfiguration,這個類,一看就是feign和ribbon整合起來的東西
@Bean
@ConditionalOnMissingBean
public Request.Options feignRequestOptions() {
return LoadBalancerFeignClient.DEFAULT_OPTIONS;
}
但是呢,遺憾的是,在這裡找到的唯一有關係的,就是這個東東,Request.Options,人家用的是預設的配置,XXXAutoConfiguration找不到,那就找XXXConfiguration。。一不小心找到了三個東西:
DefaultFeignLoadBalancedConfiguration.class
HttpClientFeignLoadBalancedConfiguration.class
OkHttpFeignLoadBalancedConfiguration.class
那麼如果出現這種情況,想都不用想,直接預設肯定是Default的,肯定是用預設的
HttpClientFeignLoadBalancedConfiguration.class,要求的是feign.httpclient.enabled屬性設定為true
OkHttpFeignLoadBalancedConfiguration.class,要求的是feign.okhttp.enabled屬性設定為true
DefaultFeignLoadBalancedConfiguration.class,預設的是這裡返回的Feign.Client
@Configuration
class DefaultFeignLoadBalancedConfiguration {
@Bean
@ConditionalOnMissingBean
public Client feignClient(CachingSpringLoadBalancerFactory cachingFactory,
SpringClientFactory clientFactory) {
return new LoadBalancerFeignClient(new Client.Default(null, null),
cachingFactory, clientFactory);
}
}
預設的就是這裡返回的LoadBalancerFeignClient。。。
下集預告,下一節直接就是,如何基於feign的核心機制,來建立介面的動態代理,Targeter