当我们在项目中调用自己实现的Feignclient负载均衡中如何起作用?请看下图:
在图一中我们可以发现,在ConsumerController中调用自定义的DemoFeignClient方法时,通过spring容器中对DemoFeignclient的代理类的调用最终通过feign.SynchronousMethodHandler.invoke()->openfeign.loadbalancer.execute()->org.springframework.cloud.loadbalancer.blocking.client.FeignBlockingLoadBalancerClient.choose()->org.springframework.cloud.loadbalancer.core.RoundRobinLoadBalancer.choose()这样的调用链,最终执行spring cloud loadbalaner中的轮询负载均横策略!
然而,上图中的这些关键类是如何组合起来发挥作用呢?请我们一起继续分析!spring cloud项目启动后,spring容器解析并加载LoadBalancerClientConfiguration.java配置文件(如下图所示)
图二
然后将"reactorServiceInstanceLoadBalancer"注册到beanDefinitionMap中。
然后会扫描我们声明的controller,因为conroller中注入了DemoFeignClient,因此spring容器会递归创建DemoFeignClient,创建DemoFiegnClient过程中会通过AbstractAutowireCapableBeanFactory.obtainFromSupplier()注入instanceSupplier实例,也就是FeignClientFactoryBean实例!
下面是org.springframework.cloud.openfeign.FeignClientsRegistrar.registerFeignClient()方法主要逻辑:
private void registerFeignClient(BeanDefinitionRegistry registry, AnnotationMetadata annotationMetadata,
Map attributes) {
//忽略非核心代码片段
BeanDefinitionBuilder definition = BeanDefinitionBuilder.genericBeanDefinition(clazz, () -> {
//设置url
factoryBean.setUrl(getUrl(beanFactory, attributes));
//设置路径
factoryBean.setPath(getPath(beanFactory, attributes));
//decode404 布尔值 factoryBean.setDecode404(Boolean.parseBoolean(String.valueOf(attributes.get("decode404"))));
Object fallback = attributes.get("fallback");
//设置fallback
if (fallback != null) {
factoryBean.setFallback(fallback instanceof Class ? (Class>) fallback
: ClassUtils.resolveClassName(fallback.toString(), null));
}
//设置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()中最终执行loadBalance();在loadBalance()中实例化FeignInvocationHandler;
在项目启动成功之后,我们调用DemoFeignClient中的方法时
图三
通过图三可以发现,描述DemoFeignClient的RootBeanDefinition的类中还有一个叫“instanceSupplier”的类型属性,它的值是“FeignClientsRegistrar$lambda”,那么这个类时什么时候被注入进来的呢?答案就是上面分析项目启动过程中spring容器根据RootBeanDefinition对DemoFeignClient的描述,通过对"FeignClientsRegistrar$lambda"的调用完成对DemoFeignClient实例的创建。
在完成创建DemoFeignClient实例后,我们调用org.springframework.cloud.openfeign.loadbalancer。FeignBlockingLoadBalancerClient.execute()执行负载均衡策略时,执行到如下代码块
Set supportedLifecycleProcessors = LoadBalancerLifecycleValidator
.getSupportedLifecycleProcessors(
loadBalancerClientFactory.getInstances(serviceId, LoadBalancerLifecycle.class),
RequestDataContext.class, ResponseData.class, ServiceInstance.class);
"loadBalancerClientFactory.getInstances(serviceId, LoadBalancerLifecycle.class)"逻辑会获取LoadBalancer实例,最终调用LoadBalancerClientConfiguration.java中的reactorServiceInstanceLoadBalancer()实现创建负载均衡实例逻辑
@Bean
@ConditionalOnMissingBean
public ReactorLoadBalancer reactorServiceInstanceLoadBalancer(Environment environment,
LoadBalancerClientFactory loadBalancerClientFactory) {
String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
//创建负载均衡实例,而且我们发现默认的负载均衡实例是轮询负载均衡实例
return new RoundRobinLoadBalancer(
loadBalancerClientFactory.getLazyProvider(name, ServiceInstanceListSupplier.class), name);
}
ok,截止到目前为止,我们的负载均衡实例已经创建完成!
这样一来,我们通过openfeign进行远程调用时,通过下图的调用链
图四
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(),这样的调用链最终根据RoundRobinLoadBalancer.choose()获取服务实例。
public Mono> choose(Request request) {
ServiceInstanceListSupplier supplier = serviceInstanceListSupplierProvider
.getIfAvailable(NoopServiceInstanceListSupplier::new);
//返回服务实例
return supplier.get(request).next()
.map(serviceInstances -> processInstanceResponse(supplier, serviceInstances));
}
拿到服务实例后,FeignBlockingLoadBalancerClient.execute()中最终通过LoadBalancerUtils.executeWithLoadBalancerLifecycleProcessing()获取响应结果!
下面是具体代码逻辑:
static Response executeWithLoadBalancerLifecycleProcessing(Client feignClient, Request.Options options,
Request feignRequest, org.springframework.cloud.client.loadbalancer.Request lbRequest,
org.springframework.cloud.client.loadbalancer.Response lbResponse,
Set supportedLifecycleProcessors, boolean loadBalanced, boolean useRawStatusCodes)
throws IOException {
supportedLifecycleProcessors.forEach(lifecycle -> lifecycle.onStartRequest(lbRequest, lbResponse));
try {
//通过openfeign调用,获取响应结果
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;
}
}