詳解openfeign集成spring?cloud?loadbalancer實現(xiàn)負載均衡流程
Feignclient負載均衡中如何起作用
當我們在項目中調(diào)用自己實現(xiàn)的Feignclient負載均衡中如何起作用?請看下圖:

圖一
在圖一中我們可以發(fā)現(xiàn),在ConsumerController中調(diào)用自定義的DemoFeignClient方法時,通過spring容器中對DemoFeignclient的代理類的調(diào)用最終通過feign.SynchronousMethodHandler.invoke()->openfeign.loadbalancer.execute()->org.springframework.cloud.loadbalancer.blocking.client.FeignBlockingLoadBalancerClient.choose()->org.springframework.cloud.loadbalancer.core.RoundRobinLoadBalancer.choose()這樣的調(diào)用鏈,最終執(zhí)行spring cloud loadbalaner中的輪詢負載均橫策略!
然而,上圖中的這些關(guān)鍵類是如何組合起來發(fā)揮作用呢?請我們一起繼續(xù)分析!spring cloud項目啟動后,spring容器解析并加載LoadBalancerClientConfiguration.java配置文件(如下圖所示)

圖二
然后將"reactorServiceInstanceLoadBalancer"注冊到beanDefinitionMap中。
然后會掃描我們聲明的controller,因為conroller中注入了DemoFeignClient,因此spring容器會遞歸創(chuàng)建DemoFeignClient,創(chuàng)建DemoFiegnClient過程中會通過AbstractAutowireCapableBeanFactory.obtainFromSupplier()注入instanceSupplier實例,也就是FeignClientFactoryBean實例!
主要邏輯
下面是org.springframework.cloud.openfeign.FeignClientsRegistrar.registerFeignClient()方法主要邏輯:
private void registerFeignClient(BeanDefinitionRegistry registry, AnnotationMetadata annotationMetadata,
Map<String, Object> attributes) {
//忽略非核心代碼片段
BeanDefinitionBuilder definition = BeanDefinitionBuilder.genericBeanDefinition(clazz, () -> {
//設(shè)置url
factoryBean.setUrl(getUrl(beanFactory, attributes));
//設(shè)置路徑
factoryBean.setPath(getPath(beanFactory, attributes));
//decode404 布爾值 factoryBean.setDecode404(Boolean.parseBoolean(String.valueOf(attributes.get("decode404"))));
Object fallback = attributes.get("fallback");
//設(shè)置fallback
if (fallback != null) {
factoryBean.setFallback(fallback instanceof Class ? (Class<?>) fallback
: ClassUtils.resolveClassName(fallback.toString(), null));
}
//設(shè)置fallback工廠類
Object fallbackFactory = attributes.get("fallbackFactory");
if (fallbackFactory != null) {
factoryBean.setFallbackFactory(fallbackFactory instanceof Class ? (Class<?>) fallbackFactory
: ClassUtils.resolveClassName(fallbackFactory.toString(), null));
}
//實例化我們聲明的DemoClient
return factoryBean.getObject();
});
}這還沒有完,org.springframework.cloud.openfeign.FeignClientFactoryBean.getObject()中最終執(zhí)行l(wèi)oadBalance();在loadBalance()中實例化FeignInvocationHandler;
調(diào)用DemoFeignClient中方法
在項目啟動成功之后,我們調(diào)用DemoFeignClient中的方法時

圖三
通過圖三可以發(fā)現(xiàn),描述DemoFeignClient的RootBeanDefinition的類中還有一個叫“instanceSupplier”的類型屬性,它的值是“FeignClientsRegistrar$lambda”,那么這個類時什么時候被注入進來的呢?答案就是上面分析項目啟動過程中spring容器根據(jù)RootBeanDefinition對DemoFeignClient的描述,通過對"FeignClientsRegistrar$lambda"的調(diào)用完成對DemoFeignClient實例的創(chuàng)建。
在完成創(chuàng)建DemoFeignClient實例后,我們調(diào)用org.springframework.cloud.openfeign.loadbalancer。
FeignBlockingLoadBalancerClient.execute()執(zhí)行負載均衡策略時,執(zhí)行到如下代碼塊
Set<LoadBalancerLifecycle> supportedLifecycleProcessors = LoadBalancerLifecycleValidator
.getSupportedLifecycleProcessors(
loadBalancerClientFactory.getInstances(serviceId, LoadBalancerLifecycle.class),
RequestDataContext.class, ResponseData.class, ServiceInstance.class);"loadBalancerClientFactory.getInstances(serviceId, LoadBalancerLifecycle.class)"邏輯會獲取LoadBalancer實例,最終調(diào)用LoadBalancerClientConfiguration.java中的reactorServiceInstanceLoadBalancer()實現(xiàn)創(chuàng)建負載均衡實例邏輯
@Bean
@ConditionalOnMissingBean
public ReactorLoadBalancer<ServiceInstance> reactorServiceInstanceLoadBalancer(Environment environment,
LoadBalancerClientFactory loadBalancerClientFactory) {
String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
//創(chuàng)建負載均衡實例,而且我們發(fā)現(xiàn)默認的負載均衡實例是輪詢負載均衡實例
return new RoundRobinLoadBalancer(
loadBalancerClientFactory.getLazyProvider(name, ServiceInstanceListSupplier.class), name);
}ok,截止到目前為止,我們的負載均衡實例已經(jīng)創(chuàng)建完成!
這樣一來,我們通過openfeign進行遠程調(diào)用時,通過下圖的調(diào)用鏈

圖四
FeignInvocationHandler.invoke()->SynchronousMethodHandler.invoke()->org.springframework.cloud.openfeign.loadbalancer.FeignBlockingLoadBalancerClient.execute()->org.springframework.cloud.loadbalancer.blocking.client.BlockingLoadBalancerClient.choose()->org.springframework.cloud.loadbalancer.core.RoundRobinLoadBalancer.choose(),這樣的調(diào)用鏈最終根據(jù)RoundRobinLoadBalancer.choose()獲取服務實例。
public Mono<Response<ServiceInstance>> choose(Request request) {
ServiceInstanceListSupplier supplier = serviceInstanceListSupplierProvider
.getIfAvailable(NoopServiceInstanceListSupplier::new);
//返回服務實例
return supplier.get(request).next()
.map(serviceInstances -> processInstanceResponse(supplier, serviceInstances));
}拿到服務實例后,F(xiàn)eignBlockingLoadBalancerClient.execute()中最終通過LoadBalancerUtils.executeWithLoadBalancerLifecycleProcessing()獲取響應結(jié)果!
下面是具體代碼邏輯:
static Response executeWithLoadBalancerLifecycleProcessing(Client feignClient, Request.Options options,
Request feignRequest, org.springframework.cloud.client.loadbalancer.Request lbRequest,
org.springframework.cloud.client.loadbalancer.Response<ServiceInstance> lbResponse,
Set<LoadBalancerLifecycle> supportedLifecycleProcessors, boolean loadBalanced, boolean useRawStatusCodes)
throws IOException {
supportedLifecycleProcessors.forEach(lifecycle -> lifecycle.onStartRequest(lbRequest, lbResponse));
try {
//通過openfeign調(diào)用,獲取響應結(jié)果
Response response = feignClient.execute(feignRequest, options);
if (loadBalanced) {
supportedLifecycleProcessors.forEach(
lifecycle -> lifecycle.onComplete(new CompletionContext<>(CompletionContext.Status.SUCCESS,
lbRequest, lbResponse, buildResponseData(response, useRawStatusCodes))));
}
return response;
}
catch (Exception exception) {
if (loadBalanced) {
supportedLifecycleProcessors.forEach(lifecycle -> lifecycle.onComplete(
new CompletionContext<>(CompletionContext.Status.FAILED, exception, lbRequest, lbResponse)));
}
throw exception;
}
}以上就是詳解openfeign集成spring cloud loadbalancer實現(xiàn)負載均衡流程的詳細內(nèi)容,更多關(guān)于spring cloud loadbalancer的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
java實現(xiàn)ThreadLocal線程局部變量的實現(xiàn)
本文主要介紹了java實現(xiàn)ThreadLocal線程局部變量的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2023-07-07
SpringBoot整合iText7導出PDF及性能優(yōu)化方式
在SpringBoot項目中整合iText7庫以導出PDF文件,不僅能夠滿足報告生成需求,而且可以處理復雜的文檔布局與樣式,整合步驟包括添加Maven依賴、編寫PDF生成代碼,性能優(yōu)化方面,建議使用流式處理、緩存樣式與字體、優(yōu)化HTML/CSS結(jié)構(gòu)、采用異步處理2024-09-09
SpringMVC整合SSM實現(xiàn)表現(xiàn)層數(shù)據(jù)封裝詳解
這篇文章主要介紹了SpringMVC整合SSM實現(xiàn)表現(xiàn)層數(shù)據(jù)封裝,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習吧2022-10-10

