在springcloud體系下服務(wù)之間的調(diào)用陪汽,目前比較常用的都是通過openfeign來進行調(diào)用昧谊,而openfeign是集成有負載均衡ribbon凤价、熔斷器hystrix的鸽斟,那今天就和大家一起探究下 openFeign是如何與ribbon和hystrix一起協(xié)作來完成一起請求過程的。
在請求過程中接口需不需要熔斷利诺,發(fā)起請求的組件會有不同的配置富蓄,我們以啟用hystrix以及okhttp的方式發(fā)起調(diào)用,如下配置
#熔斷器啟用
feign.hystrix.enabled=true
#啟用okhttp
feign.okhttp.enabled=true
先看下上面兩項配置干了些什么
首先來看feign.okhttp.enabled=true
定義了?LoadBalancerFeignClient 的Bean對象 慢逾,LoadBalancerFeignClient 中的Client對象就只在這初始化的立倍,源碼中也就是OKHttpClient對象躏吊。
再看看feign.hystrix.enabled=true
接下來,我們在這個前提下捋一捋整個調(diào)用過程帐萎,openFeign從EnableFeignClients這個注解開始的
一比伏、解析階段
看代碼import了一個類FeignClientsRegistrar,這個類實現(xiàn)了ImportBeanDefinitionRegistrar接口疆导,那么就需要重寫registerBeanDefinitions方法赁项。如下:
這個方法做了2兩件事情:
1、注冊全局配置澈段,如果EnableFeignClients注解上配置了defaultConfiguration屬性
2悠菜、注冊FeignClients
這個方法會掃描類路徑上標記@FeignClient注解的接口,根據(jù)@EnableFeignClients注解上的配置败富,并循環(huán)注冊FeignClient悔醋。
這個方法就是將FeignClient注解上的屬性信息,封裝到BeanDefinition中兽叮,并注冊到Spring容器中芬骄。
二、運行階段
在解析階段將@FeignClient注解的類以FeignClientFactoryBean的形式往BeanFactory注入BeanDefinition鹦聪。
1账阻、獲取在FeignAutoConfiguration中注入的FeignContext
2、調(diào)用feign方法泽本,獲取構(gòu)建器
protected Feign.Builder feign(FeignContext context) {
? ? FeignLoggerFactory loggerFactory = get(context, FeignLoggerFactory.class);
? ? Logger logger = loggerFactory.create(this.type);
? ? // @formatter:off
? ? Feign.Builder builder = get(context, Feign.Builder.class)
? ? ? ? ? ? // required values
? ? ? ? ? ? .logger(logger)
? ? ? ? ? ? .encoder(get(context, Encoder.class))
? ? ? ? ? ? .decoder(get(context, Decoder.class))
? ? ? ? ? ? .contract(get(context, Contract.class));
? ? // @formatter:on
? ? configureFeign(context, builder);
? ? return builder;
}
? ? 根據(jù)FeignContext處理了我們自定義的@FeignClient以及全局@EnableFeignClients中配置的日志淘太,加、解密器规丽,驗證器等蒲牧,最后configureFeign如下,處理了鏈接超時赌莺、讀取超時等配置項:
protected void configureFeign(FeignContext context, Feign.Builder builder) {
? ? FeignClientProperties properties = this.applicationContext.getBean(FeignClientProperties.class);
? ? if (properties != null) {
? ? ? ? if (properties.isDefaultToProperties()) {
? ? ? ? ? ? configureUsingConfiguration(context, builder);
? ? ? ? ? ? configureUsingProperties(
? ? ? ? ? ? ? ? ? ? properties.getConfig().get(properties.getDefaultConfig()),
? ? ? ? ? ? ? ? ? ? builder);
? ? ? ? ? ? configureUsingProperties(properties.getConfig().get(this.contextId),
? ? ? ? ? ? ? ? ? ? builder);
? ? ? ? } else {
? ? ? ? ? ? configureUsingProperties(
? ? ? ? ? ? ? ? ? ? properties.getConfig().get(properties.getDefaultConfig()),
? ? ? ? ? ? ? ? ? ? builder);
? ? ? ? ? ? configureUsingProperties(properties.getConfig().get(this.contextId),
? ? ? ? ? ? ? ? ? ? builder);
? ? ? ? ? ? configureUsingConfiguration(context, builder);
? ? ? ? }
? ? } else {
? ? ? ? configureUsingConfiguration(context, builder);
? ? }
}
3冰抢、調(diào)用loadBalance方法
4、根據(jù)Targeter(這里是HystrixTargeter)雄嚣,
調(diào)用的是feign的target方法晒屎,由于開啟了hystrix所以實際上調(diào)用的是HystrixFeign的target方法
可以看到首先調(diào)用ParseHandlersByName的apply方法構(gòu)建給每個方法都構(gòu)建一個MethodHander對象喘蟆,存儲在Map中缓升,key即為methodd對象,下面是其實現(xiàn)
這里的factory其實就是SynchronousMethodHandler的一個內(nèi)部類
進入查看create方法的實現(xiàn)
可以看到實際上返回的是SynchronousMethodHandler對象蕴轨,接下來就是
使用InvocationHandlerFactory工廠創(chuàng)建代理對象港谊,返回InvocationHandler對象實際上是HystrixInvocationHandler,最后返回代理對象橙弱。
5歧寺、HystrixInvocationHandler的invoker方法
可見openFeign是通過HystrixInvocationHandler與Hystrix協(xié)作的燥狰,構(gòu)建HystrixCommand對象,在run方法中執(zhí)行核心邏輯斜筐,如果需要降級則執(zhí)行g(shù)etFallback方法龙致。在run方法中根據(jù)method獲取MethodHandler對象,這里是SynchronousMethodHandler對象顷链,下面是invoke方法
這里調(diào)用的client的execute方法來處理請求目代,而client實際上是?LoadBalancerFeignClient,我們來看下其execute的實現(xiàn)嗤练,
再調(diào)用lbClient方法根據(jù)clientName獲取到FeignLoadBalancer對象榛了,進而調(diào)用其executeWithLoadBalancer方法
FeignLoadBalancer繼承AbstractLoadBalancerAwareClient,executeWithLoadBalancer方法在AbstractLoadBalancerAwareClient中實現(xiàn)
方法中構(gòu)建LoadBalancerCommand對象煞抬,并調(diào)用AbstractLoadBalancerAwareClient.this.execute方法霜大,也就是OkHttpLoadBalancingClient的execute方法,可見openFeign是通過LoadBalancerFeignClient實現(xiàn)與Ribbon協(xié)作的
最終通過OkHttpClient發(fā)送請求革答,并返回結(jié)果封裝到OkHttpRibbonResponse對象中战坤,
總結(jié),openFeign是通過HystrixInvocationHandler構(gòu)建HystrixCommand完成與Hystrix的協(xié)作残拐,通過LoadBalancerFeignClient實現(xiàn)與Ribbon協(xié)作的湖笨。