1. 程式人生 > >springcloud feign原始碼分析(6)——關鍵元件!找一找Feign.Client用的是誰以及居然在這裡就跟ribbon關聯了!

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