之所以只看pod模式下的服务调用链路,是因为在service模式下不会走缓存,效率低,并且负载均衡模式不能由spring cloud框架所控制,不太灵活
需要关注的几个类:
DiscoveryClient
org.springframework.cloud.loadbalancer.blocking.client.BlockingLoadBalancerClient
org.springframework.cloud.loadbalancer.blocking.client.BlockingLoadBalancerClient#choose(java.lang.String, org.springframework.cloud.client.loadbalancer.Request)
publicServiceInstancechoose(StringserviceId,Requestrequest){ReactiveLoadBalancerloadBalancer=this.loadBalancerClientFactory.getInstance(serviceId);if(loadBalancer==null){returnnull;}else{ResponseloadBalancerResponse=(Response)Mono.from(loadBalancer.choose(request)).block();returnloadBalancerResponse==null?null:(ServiceInstance)loadBalancerResponse.getServer();}}
org.springframework.cloud.loadbalancer.support.LoadBalancerClientFactory#getInstance
publicReactiveLoadBalancergetInstance(StringserviceId){return(ReactiveLoadBalancer)this.getInstance(serviceId,ReactorServiceInstanceLoadBalancer.class);}
feign调用
implements ReactorServiceInstanceLoadBalancer
feign调用时用的org.springframework.cloud.openfeign.loadbalancer.FeignBlockingLoadBalancerClient中的execute方法调用的。
其中获取服务列表的代码为:ServiceInstance instance = loadBalancerClient.choose(serviceId, lbRequest);
也就是org.springframework.cloud.loadbalancer.blocking.client.BlockingLoadBalancerClient#choose(java.lang.String, org.springframework.cloud.client.loadbalancer.Request)这个方法,其中用的此方法:
ReactiveLoadBalancer loadBalancer = this.loadBalancerClientFactory.getInstance(serviceId);
其中的loadBalancerClientFactory字段是在BlockingLoadBalancerClient初始化时设置的。需要看一下loadBalancerClientFactory传入的地方。
也就是org.springframework.cloud.openfeign.loadbalancer.FeignBlockingLoadBalancerClient类初始化时LoadBalancerClient注入进去的是哪个类。
这个类的属于commons的包里,看一下其中loadbalancer中关于初始化的地方。
代码在此处:
org.springframework.cloud.loadbalancer.config.BlockingLoadBalancerClientAutoConfiguration#blockingLoadBalancerClient
@Bean
@ConditionalOnBean(LoadBalancerClientFactory.class)
@ConditionalOnMissingBean
public LoadBalancerClient blockingLoadBalancerClient(LoadBalancerClientFactory loadBalancerClientFactory) {
return new BlockingLoadBalancerClient(loadBalancerClientFactory);
}
这里注入了一个LoadBalancerClientFactory,这经的注入代码在此处:org.springframework.cloud.loadbalancer.config.LoadBalancerAutoConfiguration#loadBalancerClientFactory
@ConditionalOnMissingBean
@Bean
public LoadBalancerClientFactory loadBalancerClientFactory(LoadBalancerClientsProperties properties) {
LoadBalancerClientFactory clientFactory = new LoadBalancerClientFactory(properties);
clientFactory.setConfigurations(this.configurations.getIfAvailable(Collections::emptyList));
return clientFactory;
}
这个factory的代码中的getInstance方法:
@Override
public ReactiveLoadBalancer getInstance(String serviceId) {
return getInstance(serviceId, ReactorServiceInstanceLoadBalancer.class);
}
获取的是ReactorServiceInstanceLoadBalancer.class
则需要找到ReactorServiceInstanceLoadBalancer的实现类:
org.springframework.cloud.loadbalancer.annotation.LoadBalancerClientConfiguration#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);
}
其中用懒加载获取的ServiceInstanceListSupplier的bean。
那么如果是service模式下,其中的ServiceInstanceListSupplier的实现类为:org.springframework.cloud.kubernetes.client.loadbalancer.KubernetesClientServicesListSupplier,其初始化代码为:
@Bean
@ConditionalOnProperty(name = "spring.cloud.kubernetes.loadbalancer.mode", havingValue = "SERVICE")
KubernetesServicesListSupplier kubernetesServicesListSupplier(Environment environment, CoreV1Api coreV1Api,
KubernetesClientServiceInstanceMapper mapper, KubernetesDiscoveryProperties discoveryProperties,
KubernetesNamespaceProvider kubernetesNamespaceProvider) {
return new KubernetesClientServicesListSupplier(environment, mapper, discoveryProperties, coreV1Api,
kubernetesNamespaceProvider);
}
如果是pod模式,则使用的默认的初始化代码:org.springframework.cloud.loadbalancer.annotation.LoadBalancerClientConfiguration.ReactiveSupportConfiguration#discoveryClientServiceInstanceListSupplier
其代码为:
@Bean
@ConditionalOnBean(ReactiveDiscoveryClient.class)
@ConditionalOnMissingBean
@Conditional(DefaultConfigurationCondition.class)
public ServiceInstanceListSupplier discoveryClientServiceInstanceListSupplier(
ConfigurableApplicationContext context) {
return ServiceInstanceListSupplier.builder().withDiscoveryClient().withCaching().build(context);
}
其中withDiscoveryClient方法:
/**
* Sets a {@link ReactiveDiscoveryClient}-based
* {@link DiscoveryClientServiceInstanceListSupplier} as a base
* {@link ServiceInstanceListSupplier} in the hierarchy.
* @return the {@link ServiceInstanceListSupplierBuilder} object
*/
public ServiceInstanceListSupplierBuilder withDiscoveryClient() {
if (baseCreator != null && LOG.isWarnEnabled()) {
LOG.warn("Overriding a previously set baseCreator with a ReactiveDiscoveryClient baseCreator.");
}
this.baseCreator = context -> {
ReactiveDiscoveryClient discoveryClient = context.getBean(ReactiveDiscoveryClient.class);
return new DiscoveryClientServiceInstanceListSupplier(discoveryClient, context.getEnvironment());
};
return this;
}
其中ReactiveDiscoveryClient的bean为:
@Bean
@ConditionalOnMissingBean
public KubernetesInformerReactiveDiscoveryClient kubernetesReactiveDiscoveryClient(
KubernetesNamespaceProvider kubernetesNamespaceProvider, SharedInformerFactory sharedInformerFactory,
Lister serviceLister, Lister endpointsLister,
SharedInformer serviceInformer, SharedInformer endpointsInformer,
KubernetesDiscoveryProperties properties) {
return new KubernetesInformerReactiveDiscoveryClient(kubernetesNamespaceProvider, sharedInformerFactory,
serviceLister, endpointsLister, serviceInformer, endpointsInformer, properties);
}
public class KubernetesInformerReactiveDiscoveryClient implements ReactiveDiscoveryClient
所以由此可以看出,k8s中pod模式下用的是KubernetesInformerReactiveDiscoveryClient。
所以如果想要到达k8s模式下的个性化定制,可以参考官方文档https://docs.spring.io/spring-cloud-commons/docs/current/reference/html/#hints-based-loadbalancing,
参考代码:
org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplierBuilder#withHints