前言
Gateway Ribbon Nacos分別屬於不同組織開發的框架,但是能共同服務於微服務框架中,它們是如何配合的呢
Gateway
1.在自動配置類GatewayDiscoveryClientAutoConfiguration中有一段代碼
@Bean @ConditionalOnProperty(name = "spring.cloud.gateway.discovery.locator.enabled") public DiscoveryClientRouteDefinitionLocator discoveryClientRouteDefinitionLocator( ReactiveDiscoveryClient discoveryClient, DiscoveryLocatorProperties properties) { return new DiscoveryClientRouteDefinitionLocator(discoveryClient, properties); }
當spring.cloud.gateway.discovery.locator.enabled為true,這段代碼會從ReactiveDiscoveryClient的實現類中獲取服務名稱列表封裝成路由定義,而Nacos中有對應的實現類為NacosReactiveDiscoveryClient,這是它們的聯系點之一
2.當外部請求進來時,例如https://host/服務名/xxx,會經過一個全局過濾器,為LoadBalancerClientFilter,這個過濾器的作用是將url的服務名稱改成真正服務所在的ip,里面有段關鍵代碼是
protected ServiceInstance choose(ServerWebExchange exchange) { return loadBalancer.choose( ((URI) exchange.getAttribute(GATEWAY_REQUEST_URL_ATTR)).getHost()); }
上面起作用的是loadBalancer,對應的類型是LoadBalancerClient,這個是gateway框架定義的接口,真正實現類是Ribbon的RibbonLoadBalancerClient,這是gateway和ribbon的關聯點
Ribbon
再來看看RibbonLoadBalancerClient的choose方法
public ServiceInstance choose(String serviceId, Object hint) { Server server = getServer(getLoadBalancer(serviceId), hint); if (server == null) { return null; } return new RibbonServer(serviceId, server, isSecure(server, serviceId), serverIntrospector(serviceId).getMetadata(server)); }
上面關鍵代碼是getLoadBalancer(serviceId),如下
protected ILoadBalancer getLoadBalancer(String serviceId) { return this.clientFactory.getLoadBalancer(serviceId); }
這段代碼目的是取出ILoadBalancer的實現類,其為ZoneAwareLoadBalancer,而它又是繼承DynamicServerListLoadBalancer,構造函數如下
public DynamicServerListLoadBalancer(IClientConfig clientConfig, IRule rule, IPing ping, ServerList<T> serverList, ServerListFilter<T> filter, ServerListUpdater serverListUpdater) { super(clientConfig, rule, ping); this.serverListImpl = serverList; this.filter = filter; this.serverListUpdater = serverListUpdater; if (filter instanceof AbstractServerListFilter) { ((AbstractServerListFilter) filter).setLoadBalancerStats(getLoadBalancerStats()); } restOfInit(clientConfig); }
上面的構造函數會自動注入類型ServerList<T>的serverList,而nacos的NacosServerList實現了其接口,這里就是ribbon和nacos的連接點.
nacos
再來看看nacos什么時候提供了NacosServerList,看下面配置類
@Configuration(proxyBeanMethods = false) @ConditionalOnRibbonNacos public class NacosRibbonClientConfiguration { @Autowired private PropertiesFactory propertiesFactory; @Bean @ConditionalOnMissingBean public ServerList<?> ribbonServerList(IClientConfig config, NacosDiscoveryProperties nacosDiscoveryProperties) { if (this.propertiesFactory.isSet(ServerList.class, config.getClientName())) { ServerList serverList = this.propertiesFactory.get(ServerList.class, config, config.getClientName()); return serverList; } NacosServerList serverList = new NacosServerList(nacosDiscoveryProperties); serverList.initWithNiwsConfig(config); return serverList; } @Bean @ConditionalOnMissingBean public NacosServerIntrospector nacosServerIntrospector() { return new NacosServerIntrospector(); } }
在此配置類中,nacos提供了NacosServerList.另外,NacosServerList里面有方法getServers
private List<NacosServer> getServers() { try { String group = discoveryProperties.getGroup(); List<Instance> instances = discoveryProperties.namingServiceInstance() .selectInstances(serviceId, group, true); return instancesToServerList(instances); } catch (Exception e) { throw new IllegalStateException( "Can not get service instances from nacos, serviceId=" + serviceId, e); } }
selectInstances方法主要邏輯是向nacosserver發起http請求,獲取服務的地址列表.