1. spring-cloud 之 RestTemplate与@Loadbalanced

1. restTemplate是spring实现的,基于restful风格的http请求模板。使用restTemplate可以简化请求操作的复杂性,同时规范了代码风格。

2. restTemplate不加@Loadbalanced注解,会根据url去请求,需要明确域名或者ip地址,如果写的是服务名称,例如:http://SERVICE_ORDER/list, 会报错:java.net.UnknownHostException

3. restTemplate加了@Loadbalanced注解,就会通过loadbalacer去将SERVICE_ORDER解析成相应的ip+端口号,并且实现负载均衡

加下来就来分析,

定义restTemplate的bean

    @Bean
    @LoadBalanced//追加ribbon负载功能
    public RestTemplate createRestTemplate(){
        return new RestTemplate();
    }

接着来分析@LoadBalanced注解

位于spring-cloud-commons包下

org.springframework.cloud.client.loadbalancer.LoadBalancerAutoConfiguration


@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(RestTemplate.class) // 有TestTemplate.class才会去加载这个configuration
@ConditionalOnBean(LoadBalancerClient.class) //有loadBalancerClient.class 才会去加载
@EnableConfigurationProperties(LoadBalancerRetryProperties.class)
public class LoadBalancerAutoConfiguration {

	@LoadBalanced
	@Autowired(required = false)
	private List restTemplates = Collections.emptyList();

	@Autowired(required = false)
	private List transformers = Collections.emptyList();

	@Bean
	public SmartInitializingSingleton loadBalancedRestTemplateInitializerDeprecated(
			final ObjectProvider> restTemplateCustomizers) {
		return () -> restTemplateCustomizers.ifAvailable(customizers -> {
			for (RestTemplate restTemplate : LoadBalancerAutoConfiguration.this.restTemplates) {
				for (RestTemplateCustomizer customizer : customizers) {
					customizer.customize(restTemplate);
				}
			}
		});
	}

	@Bean
	@ConditionalOnMissingBean
	public LoadBalancerRequestFactory loadBalancerRequestFactory(
			LoadBalancerClient loadBalancerClient) {
		return new LoadBalancerRequestFactory(loadBalancerClient, this.transformers);
	}

	@Configuration(proxyBeanMethods = false)
	@ConditionalOnMissingClass("org.springframework.retry.support.RetryTemplate")
	static class LoadBalancerInterceptorConfig {

		@Bean
		public LoadBalancerInterceptor ribbonInterceptor(
				LoadBalancerClient loadBalancerClient,
				LoadBalancerRequestFactory requestFactory) {
				// 构建loadBalancerInterceptor拦截器
			return new LoadBalancerInterceptor(loadBalancerClient, requestFactory);
		}

		@Bean
		@ConditionalOnMissingBean
		public RestTemplateCustomizer restTemplateCustomizer(
				final LoadBalancerInterceptor loadBalancerInterceptor) {
			return restTemplate -> {
				List list = new ArrayList<>(
						restTemplate.getInterceptors());
						// 将LoadBalancerInterceptor保存到restTemplate的拦截器中
				list.add(loadBalancerInterceptor);
				restTemplate.setInterceptors(list);
			};
		}

	}

	...

}

如果加了@LoadBalanced注解,就会往restTemplate里添加一个拦截器LoadBalancerInterceptor

以restTemplate.getForObject()为例

@Override
	@Nullable
	public  T getForObject(String url, Class responseType, Object... uriVariables) throws RestClientException {
		RequestCallback requestCallback = acceptHeaderRequestCallback(responseType);
		HttpMessageConverterExtractor responseExtractor =
				new HttpMessageConverterExtractor<>(responseType, getMessageConverters(), logger);
		return execute(url, HttpMethod.GET, requestCallback, responseExtractor, uriVariables);
	}


	@Override
	@Nullable
	public  T execute(String url, HttpMethod method, @Nullable RequestCallback requestCallback,
			@Nullable ResponseExtractor responseExtractor, Object... uriVariables) throws RestClientException {

		URI expanded = getUriTemplateHandler().expand(url, uriVariables);
		return doExecute(expanded, method, requestCallback, responseExtractor);
	}

	@Nullable
	protected  T doExecute(URI url, @Nullable HttpMethod method, @Nullable RequestCallback requestCallback,
			@Nullable ResponseExtractor responseExtractor) throws RestClientException {

		Assert.notNull(url, "URI is required");
		Assert.notNull(method, "HttpMethod is required");
		ClientHttpResponse response = null;
		try {
			ClientHttpRequest request = createRequest(url, method);
			if (requestCallback != null) {
				requestCallback.doWithRequest(request);
			}
			// 加了@LoadBalanced注解之后,request为:InterceptingClientHttpRequest
			response = request.execute();
			handleResponse(url, method, response);
			return (responseExtractor != null ? responseExtractor.extractData(response) : null);
		}
		catch (IOException ex) {
			String resource = url.toString();
			String query = url.getRawQuery();
			resource = (query != null ? resource.substring(0, resource.indexOf('?')) : resource);
			throw new ResourceAccessException("I/O error on " + method.name() +
					" request for \"" + resource + "\": " + ex.getMessage(), ex);
		}
		finally {
			if (response != null) {
				response.close();
			}
		}
	}

    org.springframework.http.client.support.HttpAccessor#createRequest

protected ClientHttpRequest createRequest(URI url, HttpMethod method) throws IOException {
		// 创建request,
		// 如果restTemplate中有拦截器,factory为:InterceptingClientHttpRequestFactory
		// 没有拦截器的话,就是SimpleClientHttpRequestFactory
		ClientHttpRequest request = getRequestFactory().createRequest(url, method);
		initialize(request);
		if (logger.isDebugEnabled()) {
			logger.debug("HTTP " + method.name() + " " + url);
		}
		return request;
	}

org.springframework.http.client.support.HttpAccessor#getRequestFactory
private ClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory(); 


	public ClientHttpRequestFactory getRequestFactory() {
		return this.requestFactory;
	}

RestTemplate extends InterceptingHttpAccessor --> abstract class InterceptingHttpAccessor extends HttpAccessor
    InterceptingHttpAccessor覆盖了HttpAccessor的getRequestFactory()
    org.springframework.http.client.support.InterceptingHttpAccessor#getRequestFactory

	@Override
	public ClientHttpRequestFactory getRequestFactory() {
		// 获取拦截器,如果拦截器为空,就走父类的getRequestFactory,即返回SimpleClientHttpRequestFactory
		// 如果拦截器不为空,就走InterceptingClientHttpRequestFactory
		List interceptors = getInterceptors();
		if (!CollectionUtils.isEmpty(interceptors)) {
			ClientHttpRequestFactory factory = this.interceptingRequestFactory;
			if (factory == null) {
				factory = new InterceptingClientHttpRequestFactory(super.getRequestFactory(), interceptors);
				this.interceptingRequestFactory = factory;
			}
			return factory;
		}
		else {
			return super.getRequestFactory();
		}
	}

    前面分析了@LoadBalanced注解,会往restTemplate里添加一个拦截器LoadBalancerInterceptor,所以这里返回的是InterceptingClientHttpRequestFactory
    org.springframework.http.client.InterceptingClientHttpRequestFactory#createRequest
 

protected ClientHttpRequest createRequest(URI uri, HttpMethod httpMethod, ClientHttpRequestFactory requestFactory) {
		// 创建的时候,将拦截器传入进去
		return new InterceptingClientHttpRequest(requestFactory, this.interceptors, uri, httpMethod);
	}

经过分析,加了@LoadBaclanced注解之后,request变成了InterceptingClientHttpRequest,
    接下来分析:

    response = request.execute();

org.springframework.http.client.AbstractClientHttpRequest#execute

@Override
	public final ClientHttpResponse execute() throws IOException {
		assertNotExecuted();
		ClientHttpResponse result = executeInternal(this.headers);
		this.executed = true;
		return result;
	}

  org.springframework.http.client.AbstractBufferingClientHttpRequest#executeInternal(org.springframework.http.HttpHeaders)

	@Override
	protected ClientHttpResponse executeInternal(HttpHeaders headers) throws IOException {
		byte[] bytes = this.bufferedOutput.toByteArray();
		if (headers.getContentLength() < 0) {
			headers.setContentLength(bytes.length);
		}
		ClientHttpResponse result = executeInternal(headers, bytes);
		this.bufferedOutput = new ByteArrayOutputStream(0);
		return result;
	}

org.springframework.http.client.InterceptingClientHttpRequest#executeInternal

protected final ClientHttpResponse executeInternal(HttpHeaders headers, byte[] bufferedOutput) throws IOException {
		InterceptingRequestExecution requestExecution = new InterceptingRequestExecution();
		return requestExecution.execute(this, bufferedOutput);
	}

 org.springframework.http.client.InterceptingClientHttpRequest.InterceptingRequestExecution#execute
 

@Override
	public ClientHttpResponse execute(HttpRequest request, byte[] body) throws IOException {
		// 遍历拦截器,前面分析了@LoadBalanced注解,会往restTemplate里添加一个拦截器LoadBalancerInterceptor
		if (this.iterator.hasNext()) {
			ClientHttpRequestInterceptor nextInterceptor = this.iterator.next();
			return nextInterceptor.intercept(request, body, this);
		}
		else {
			HttpMethod method = request.getMethod();
			Assert.state(method != null, "No standard HTTP method");
			ClientHttpRequest delegate = requestFactory.createRequest(request.getURI(), method);
			request.getHeaders().forEach((key, value) -> delegate.getHeaders().addAll(key, value));
			if (body.length > 0) {
				if (delegate instanceof StreamingHttpOutputMessage) {
					StreamingHttpOutputMessage streamingOutputMessage = (StreamingHttpOutputMessage) delegate;
					streamingOutputMessage.setBody(outputStream -> StreamUtils.copy(body, outputStream));
				}
				else {
					StreamUtils.copy(body, delegate.getBody());
				}
			}
			return delegate.execute();
		}
	}	

org.springframework.cloud.client.loadbalancer.LoadBalancerInterceptor#intercept 

@Override
	public ClientHttpResponse intercept(final HttpRequest request, final byte[] body,
			final ClientHttpRequestExecution execution) throws IOException {
		final URI originalUri = request.getURI();
		String serviceName = originalUri.getHost();
		Assert.state(serviceName != null,
				"Request URI does not contain a valid hostname: " + originalUri);
		return this.loadBalancer.execute(serviceName,
				this.requestFactory.createRequest(request, body, execution));
	}

通过调用loadBalancer来执行execute()

开始来分析@LoadBalanced注解

spring-cloud-netflix-ribbon:2.2.5-RELEASE

@Configuration
@Conditional({RibbonAutoConfiguration.RibbonClassesConditions.class})
@RibbonClients
@AutoConfigureAfter(
    name = {"org.springframework.cloud.netflix.eureka.EurekaClientAutoConfiguration"}
)
@AutoConfigureBefore({LoadBalancerAutoConfiguration.class, AsyncLoadBalancerAutoConfiguration.class})
@EnableConfigurationProperties({RibbonEagerLoadProperties.class, ServerIntrospectorProperties.class})
public class RibbonAutoConfiguration {
    ...

    @Bean
    @ConditionalOnMissingBean({LoadBalancerClient.class})
    public LoadBalancerClient loadBalancerClient() {
        return new RibbonLoadBalancerClient(this.springClientFactory());
    }

    ...
}

new LoadBalancerInterceptor(loadBalancerClient, requestFactory);

loadBalancerInterceptor里面的loadBalancer就是这个RibbonLoadBalancerClient了

org.springframework.cloud.netflix.ribbon.RibbonLoadBalancerClient#execute(java.lang.String, org.springframework.cloud.client.loadbalancer.LoadBalancerRequest)

@Override
	public  T execute(String serviceId, LoadBalancerRequest request)
			throws IOException {
		return execute(serviceId, request, null);
	}
	public  T execute(String serviceId, LoadBalancerRequest request, Object hint)
			throws IOException {
		ILoadBalancer loadBalancer = getLoadBalancer(serviceId);
		Server server = getServer(loadBalancer, hint);
		if (server == null) {
			throw new IllegalStateException("No instances available for " + serviceId);
		}
		RibbonServer ribbonServer = new RibbonServer(serviceId, server,
				isSecure(server, serviceId),
				serverIntrospector(serviceId).getMetadata(server));

		return execute(serviceId, ribbonServer, request);
	}
protected ILoadBalancer getLoadBalancer(String serviceId) {
		return this.clientFactory.getLoadBalancer(serviceId);
	}

	public ILoadBalancer getLoadBalancer(String name) {
		return getInstance(name, ILoadBalancer.class);
	}

	@Override
	public  C getInstance(String name, Class type) {
		C instance = super.getInstance(name, type);
		if (instance != null) {
			return instance;
		}
		IClientConfig config = getInstance(name, IClientConfig.class);
		return instantiateWithConfig(getContext(name), type, config);
	}

    这里其实就是找ILoadBalancer 的bean
    org.springframework.cloud.netflix.ribbon.RibbonClientConfiguration#ribbonLoadBalancer

@Bean
	@ConditionalOnMissingBean
	public ILoadBalancer ribbonLoadBalancer(IClientConfig config,
			ServerList serverList, ServerListFilter serverListFilter,
			IRule rule, IPing ping, ServerListUpdater serverListUpdater) {
		if (this.propertiesFactory.isSet(ILoadBalancer.class, name)) {
			return this.propertiesFactory.get(ILoadBalancer.class, config, name);
		}
		return new ZoneAwareLoadBalancer<>(config, rule, ping, serverList,
				serverListFilter, serverListUpdater);
	}

最终返回的是ZoneAwareLoadBalancer
    但是还有一些参数
    IClientConfig

    org.springframework.cloud.netflix.ribbon.RibbonClientConfiguration#ribbonClientConfig
 

@Bean
	@ConditionalOnMissingBean
	public IClientConfig ribbonClientConfig() {
		DefaultClientConfigImpl config = new DefaultClientConfigImpl();
		config.loadProperties(this.name);
		config.set(CommonClientConfigKey.ConnectTimeout, DEFAULT_CONNECT_TIMEOUT);
		config.set(CommonClientConfigKey.ReadTimeout, DEFAULT_READ_TIMEOUT);
		config.set(CommonClientConfigKey.GZipPayload, DEFAULT_GZIP_PAYLOAD);
		return config;
	}

serverList
    

@Bean
    @ConditionalOnMissingBean
    @SuppressWarnings("unchecked")
    public ServerList ribbonServerList(IClientConfig config) {
        if (this.propertiesFactory.isSet(ServerList.class, name)) {
            return this.propertiesFactory.get(ServerList.class, config, name);
        }
        ConfigurationBasedServerList serverList = new ConfigurationBasedServerList();
        serverList.initWithNiwsConfig(config);
        return serverList;
    }


    serverListFilter
    org.springframework.cloud.netflix.ribbon.RibbonClientConfiguration#ribbonServerListFilter

    @Bean
    @ConditionalOnMissingBean
    @SuppressWarnings("unchecked")
    public ServerListFilter ribbonServerListFilter(IClientConfig config) {
        if (this.propertiesFactory.isSet(ServerListFilter.class, name)) {
            return this.propertiesFactory.get(ServerListFilter.class, config, name);
        }
        ZonePreferenceServerListFilter filter = new ZonePreferenceServerListFilter();
        filter.initWithNiwsConfig(config);
        return filter;
    }


    rule
    org.springframework.cloud.netflix.ribbon.RibbonClientConfiguration#ribbonRule
    

@Bean
    @ConditionalOnMissingBean
    public IRule ribbonRule(IClientConfig config) {
        if (this.propertiesFactory.isSet(IRule.class, name)) {
            return this.propertiesFactory.get(IRule.class, config, name);
        }
        ZoneAvoidanceRule rule = new ZoneAvoidanceRule();
        rule.initWithNiwsConfig(config);
        return rule;
    }

    ping
    org.springframework.cloud.netflix.ribbon.RibbonClientConfiguration#ribbonPing
  

 @Bean
    @ConditionalOnMissingBean
    public IPing ribbonPing(IClientConfig config) {
        if (this.propertiesFactory.isSet(IPing.class, name)) {
            return this.propertiesFactory.get(IPing.class, config, name);
        }
        return new DummyPing();
    }

    serverListUpdater
    org.springframework.cloud.netflix.ribbon.RibbonClientConfiguration#ribbonServerListUpdater
    

@Bean
    @ConditionalOnMissingBean
    public ServerListUpdater ribbonServerListUpdater(IClientConfig config) {
        return new PollingServerListUpdater(config);
    }


    但是我这里用的是nacos,
    spring-cloud-starter-alibaba-nacos-discovery
    覆盖了serverList
    com.alibaba.cloud.nacos.ribbon.NacosRibbonClientConfiguration#ribbonServerList
    

@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;
    }

    继续分析:RibbonLoadBalancerClient.execute()

public  T execute(String serviceId, LoadBalancerRequest request, Object hint)
            throws IOException {
        // ZoneAwareLoadBalancer
        ILoadBalancer loadBalancer = getLoadBalancer(serviceId);
        Server server = getServer(loadBalancer, hint);
        if (server == null) {
            throw new IllegalStateException("No instances available for " + serviceId);
        }
        RibbonServer ribbonServer = new RibbonServer(serviceId, server,
                isSecure(server, serviceId),
                serverIntrospector(serviceId).getMetadata(server));

        return execute(serviceId, ribbonServer, request);
    }


    // hint = null
  

 protected Server getServer(ILoadBalancer loadBalancer, Object hint) {
        if (loadBalancer == null) {
            return null;
        }
        // Use 'default' on a null hint, or just pass it on?
        return loadBalancer.chooseServer(hint != null ? hint : "default");
    }

    //ENABLE 默认为true
    private static final DynamicBooleanProperty ENABLED = DynamicPropertyFactory.getInstance().getBooleanProperty("ZoneAwareNIWSDiscoveryLoadBalancer.enabled", true);

   

@Override
    public Server chooseServer(Object key) {
        // 默认没有分区,所以走if里面的super.chooseServer(key)
        if (!ENABLED.get() || getLoadBalancerStats().getAvailableZones().size() <= 1) {
            logger.debug("Zone aware logic disabled or there is only one zone");
            return super.chooseServer(key);
        }
        // 多个分区的时候
        ...
    }

    com.netflix.loadbalancer.BaseLoadBalancer#chooseServer
   

public Server chooseServer(Object key) {
        if (counter == null) {
            counter = createCounter();
        }
        counter.increment();
        // rule=ZoneAvoidanceRule
        if (rule == null) {
            return null;
        } else {
            try {
                return rule.choose(key);
            } catch (Exception e) {
                logger.warn("LoadBalancer [{}]:  Error choosing server for key {}", name, key, e);
                return null;
            }
        }
    }

    之前分析了rule=ZoneAvoidanceRule
    ZoneAvoidanceRule extends PredicateBasedRule
    com.netflix.loadbalancer.PredicateBasedRule#choose
     

@Override
    public Server choose(Object key) {
        // ZoneAwareLoadBalancer
        ILoadBalancer lb = getLoadBalancer();
        // lb.getAllServers()获取所有的实例列表
        Optional server = getPredicate().chooseRoundRobinAfterFiltering(lb.getAllServers(), key);
        if (server.isPresent()) {
            return server.get();
        } else {
            return null;
        }       
    }

    DynamicServerListLoadBalancer extends BaseLoadBalancer
    com.netflix.loadbalancer.BaseLoadBalancer#getAllServers
   

@Override
    public List getAllServers() {
        return Collections.unmodifiableList(allServerList);
    }

    @Monitor(name = PREFIX + "AllServerList", type = DataSourceType.INFORMATIONAL)
    protected volatile List allServerList = Collections
            .synchronizedList(new ArrayList());

    allServerList是空的,回到之前初始化ZoneAwareLoadBalancer的时候,传入了一个serverListUpdater
       

public DynamicServerListLoadBalancer(IClientConfig clientConfig, IRule rule, IPing ping,
                                         ServerList serverList, ServerListFilter 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);
    }

   

 void restOfInit(IClientConfig clientConfig) {
         // 默认false
        boolean primeConnection = this.isEnablePrimingConnections();
        // turn this off to avoid duplicated asynchronous priming done in BaseLoadBalancer.setServerList()
        this.setEnablePrimingConnections(false);
        // 开启定时任务,更新服务实例列表
        // 延迟1s后开始,周期是30s一次
        enableAndInitLearnNewServersFeature();
        // 立即更新一次服务实例列表
        updateListOfServers();
        if (primeConnection && this.getPrimeConnections() != null) {
            this.getPrimeConnections()
                    .primeConnections(getReachableServers());
        }
        this.setEnablePrimingConnections(primeConnection);
        LOGGER.info("DynamicServerListLoadBalancer for client {} initialized: {}", clientConfig.getClientName(), this.toString());
    }

   

 public void enableAndInitLearnNewServersFeature() {
        LOGGER.info("Using serverListUpdater {}", serverListUpdater.getClass().getSimpleName());
        // PollingServerListUpdater
        serverListUpdater.start(updateAction);
    }

    com.netflix.loadbalancer.PollingServerListUpdater#start
 

  @Override
    public synchronized void start(final UpdateAction updateAction) {
        // cas设置状态
        if (isActive.compareAndSet(false, true)) {
            final Runnable wrapperRunnable = new Runnable() {
                @Override
                public void run() {
                    if (!isActive.get()) {
                        if (scheduledFuture != null) {
                            scheduledFuture.cancel(true);
                        }
                        return;
                    }
                    try {
                        // 执行更新操作
                        updateAction.doUpdate();
                        lastUpdated = System.currentTimeMillis();
                    } catch (Exception e) {
                        logger.warn("Failed one update cycle", e);
                    }
                }
            };
            // 提交定时任务
            scheduledFuture = getRefreshExecutor().scheduleWithFixedDelay(
                    wrapperRunnable,
                    // 延迟1s执行,
                    initialDelayMs,
                    // 更新周期,默认30s
                    refreshIntervalMs,
                    TimeUnit.MILLISECONDS
            );
        } else {
            logger.info("Already active, no-op");
        }
    }

    // updateAction
    com.netflix.loadbalancer.DynamicServerListLoadBalancer#updateAction
   

 protected final ServerListUpdater.UpdateAction updateAction = new ServerListUpdater.UpdateAction() {
        @Override
        public void doUpdate() {
            updateListOfServers();
        }
    };

    com.netflix.loadbalancer.DynamicServerListLoadBalancer#updateListOfServers
   

public void updateListOfServers() {
        List servers = new ArrayList();
        if (serverListImpl != null) {
            // 通过serverListImpl来获取服务列表
            // nacos --> NacosServerList
            servers = serverListImpl.getUpdatedListOfServers();
            LOGGER.debug("List of Servers for {} obtained from Discovery client: {}",
                    getIdentifier(), servers);
            // filter -> ZonePreferenceServerListFilter
            if (filter != null) {
                servers = filter.getFilteredListOfServers(servers);
                LOGGER.debug("Filtered List of Servers for {} obtained from Discovery client: {}",
                        getIdentifier(), servers);
            }
        }
        updateAllServerList(servers);
    }

    com.alibaba.cloud.nacos.ribbon.NacosServerList#getUpdatedListOfServers
   

@Override
    public List getUpdatedListOfServers() {
        return getServers();
    }

    

private List getServers() {
        try {
            // DEFAULT_GROUP
            String group = discoveryProperties.getGroup();
            // 通过namingServiceInstace来获取serviceId的实例列表
            // selectInstances就是nacos的api了,true代表只拉取健康的实例
            List instances = discoveryProperties.namingServiceInstance()
                    .selectInstances(serviceId, group, true);
            // 转成nacosServer
            return instancesToServerList(instances);
        }
        catch (Exception e) {
            throw new IllegalStateException(
                    "Can not get service instances from nacos, serviceId=" + serviceId,
                    e);
        }
    }


    org.springframework.cloud.netflix.ribbon.ZonePreferenceServerListFilter#getFilteredListOfServers
    

@Override
    public List getFilteredListOfServers(List servers) {
        // 默认output=servers
        List output = super.getFilteredListOfServers(servers);
        // 默认zone = null
        if (this.zone != null && output.size() == servers.size()) {
            List local = new ArrayList<>();
            for (Server server : output) {
                if (this.zone.equalsIgnoreCase(server.getZone())) {
                    local.add(server);
                }
            }
            if (!local.isEmpty()) {
                return local;
            }
        }
        return output;
    }

    super.getFilteredListOfServers() --> com.netflix.loadbalancer.ZoneAffinityServerListFilter#getFilteredListOfServers
      

 @Override
    public List getFilteredListOfServers(List servers) {
        // 默认zone=null, zoneAffinity=false, zoneExclusive=false
        if (zone != null && (zoneAffinity || zoneExclusive) && servers !=null && servers.size() > 0){
            List filteredServers = Lists.newArrayList(Iterables.filter(
                    servers, this.zoneAffinityPredicate.getServerOnlyPredicate()));
            if (shouldEnableZoneAffinity(filteredServers)) {
                return filteredServers;
            } else if (zoneAffinity) {
                overrideCounter.increment();
            }
        }
        return servers;
    }

    com.netflix.loadbalancer.DynamicServerListLoadBalancer#updateAllServerList
   

protected void updateAllServerList(List ls) {
        // other threads might be doing this - in which case, we pass
        if (serverListUpdateInProgress.compareAndSet(false, true)) {
            try {
                for (T s : ls) {
                    // 设置为可用状态
                    s.setAlive(true); // set so that clients can start using these
                                      // servers right away instead
                                      // of having to wait out the ping cycle.
                }
                // 保存实例列表
                setServersList(ls);
                // 检查ping
                super.forceQuickPing();
            } finally {
                serverListUpdateInProgress.set(false);
            }
        }
    }

    com.netflix.loadbalancer.DynamicServerListLoadBalancer#setServersList
   

 public void setServersList(List lsrv) {
         // 调用父类的方法,主要是复制给allServerList和upServerList
        super.setServersList(lsrv);
        List serverList = (List) lsrv;
        Map> serversInZones = new HashMap>();
        for (Server server : serverList) {
            // make sure ServerStats is created to avoid creating them on hot
            // path
            // 主要确保serverStatsCache有server状态的缓存
            getLoadBalancerStats().getSingleServerStat(server);
            // 接下来就主要是吧server按zone划分一下,但是默认zone=UNKONW
            // 所以各个服务都在一个zone下面
            String zone = server.getZone();
            // 默认UNKNOW
            if (zone != null) {
                zone = zone.toLowerCase();
                List servers = serversInZones.get(zone);
                if (servers == null) {
                    servers = new ArrayList();
                    serversInZones.put(zone, servers);
                }
                servers.add(server);
            }
        }
        setServerListForZones(serversInZones);
    }

    supersetServerList() --> com.netflix.loadbalancer.BaseLoadBalancer#setServersList
   

public void setServersList(List lsrv) {
        // 获取读锁
        Lock writeLock = allServerLock.writeLock();
        logger.debug("LoadBalancer [{}]: clearing server list (SET op)", name);
        
        ArrayList newServers = new ArrayList();
        writeLock.lock();
        try {
            ArrayList allServers = new ArrayList();
            for (Object server : lsrv) {
                if (server == null) {
                    continue;
                }
                // nacos --> NacosServer extends Server
                if (server instanceof String) {
                    server = new Server((String) server);
                }

                if (server instanceof Server) {
                    logger.debug("LoadBalancer [{}]:  addServer [{}]", name, ((Server) server).getId());
                    allServers.add((Server) server);
                } else {
                    throw new IllegalArgumentException(
                            "Type String or Server expected, instead found:"
                                    + server.getClass());
                }

            }
            boolean listChanged = false;
            if (!allServerList.equals(allServers)) {
                listChanged = true;
                // changeListeners =[] 默认
                if (changeListeners != null && changeListeners.size() > 0) {
                   List oldList = ImmutableList.copyOf(allServerList);
                   List newList = ImmutableList.copyOf(allServers);                   
                   for (ServerListChangeListener l: changeListeners) {
                       try {
                           l.serverListChanged(oldList, newList);
                       } catch (Exception e) {
                           logger.error("LoadBalancer [{}]: Error invoking server list change listener", name, e);
                       }
                   }
                }
            }
            //默认false
            if (isEnablePrimingConnections()) {
                for (Server server : allServers) {
                    if (!allServerList.contains(server)) {
                        server.setReadyToServe(false);
                        newServers.add((Server) server);
                    }
                }
                if (primeConnections != null) {
                    primeConnections.primeConnectionsAsync(newServers, this);
                }
            }
            // This will reset readyToServe flag to true on all servers
            // regardless whether
            // previous priming connections are success or not
            // 赋值给 allServerList
            allServerList = allServers;
            // 默认true
            if (canSkipPing()) {
                for (Server s : allServerList) {
                    // 设置服务为健康状态
                    s.setAlive(true);
                }
                // 赋值给健康的服务列表
                upServerList = allServerList;
            } else if (listChanged) {
                forceQuickPing();
            }
        } finally {
            // 释放写锁
            writeLock.unlock();
        }
    }

     

 public void forceQuickPing() {
        if (canSkipPing()) {
            return;
        }
        logger.debug("LoadBalancer [{}]:  forceQuickPing invoking", name);
        
        try {
            new Pinger(pingStrategy).runPinger();
        } catch (Exception e) {
            logger.error("LoadBalancer [{}]: Error running forceQuickPing()", name, e);
        }
    }
   private boolean canSkipPing() {
        if (ping == null
                || ping.getClass().getName().equals(DummyPing.class.getName())) {
            // default ping, no need to set up timer
            return true;
        } else {
            return false;
        }
    }


    // nacos api
    com.alibaba.nacos.client.naming.NacosNamingService#selectInstances(java.lang.String, java.lang.String, boolean)

 public List selectInstances(String serviceName, String groupName, boolean healthy) throws NacosException {
        // 最后一个true代表订阅
        return selectInstances(serviceName, groupName, healthy, true);
    }


    到这里就完成了服务的定时拉取了,默认30s一次,拉取完,就交给rule进去server的选取了

    回到之前的rule.choose()
    ZoneAvoidanceRule extends PredicateBasedRule
    com.netflix.loadbalancer.PredicateBasedRule#choose
     

@Override
    public Server choose(Object key) {
        // ZoneAwareLoadBalancer
        ILoadBalancer lb = getLoadBalancer();
        // lb.getAllServers()获取所有的实例列表
        Optional server = getPredicate().chooseRoundRobinAfterFiltering(lb.getAllServers(), key);
        if (server.isPresent()) {
            return server.get();
        } else {
            return null;
        }       
    }

    com.netflix.loadbalancer.ZoneAvoidanceRule#getPredicate
   

@Override
    public AbstractServerPredicate getPredicate() {
        return compositePredicate;
    }    

   

  public ZoneAvoidanceRule() {
        super();
        ZoneAvoidancePredicate zonePredicate = new ZoneAvoidancePredicate(this);
        AvailabilityPredicate availabilityPredicate = new AvailabilityPredicate(this);
        compositePredicate = createCompositePredicate(zonePredicate, availabilityPredicate);
    }


 

   private CompositePredicate createCompositePredicate(ZoneAvoidancePredicate p1, AvailabilityPredicate p2) {
        return CompositePredicate.withPredicates(p1, p2)
                             .addFallbackPredicate(p2)
                             .addFallbackPredicate(AbstractServerPredicate.alwaysTrue())
                             .build();
        
    }


    CompositePredicate.chooseRoundRobinAfterFiltering
    CompositePredicate extends AbstractServerPredicate
    com.netflix.loadbalancer.AbstractServerPredicate#chooseRoundRobinAfterFiltering(java.util.List, java.lang.Object)
   

 public Optional chooseRoundRobinAfterFiltering(List servers, Object loadBalancerKey) {
        List eligible = getEligibleServers(servers, loadBalancerKey);
        if (eligible.size() == 0) {
            return Optional.absent();
        }
        return Optional.of(eligible.get(incrementAndGetModulo(eligible.size())));
    }

    com.netflix.loadbalancer.CompositePredicate#getEligibleServers
     

@Override
    public List getEligibleServers(List servers, Object loadBalancerKey) {
        List result = super.getEligibleServers(servers, loadBalancerKey);
        Iterator i = fallbacks.iterator();
        while (!(result.size() >= minimalFilteredServers && result.size() > (int) (servers.size() * minimalFilteredPercentage))
                && i.hasNext()) {
            AbstractServerPredicate predicate = i.next();
            result = predicate.getEligibleServers(servers, loadBalancerKey);
        }
        return result;
    }

    supper.getEligibleServers() --> com.netflix.loadbalancer.AbstractServerPredicate#getEligibleServers(java.util.List, java.lang.Object)
   

 public List getEligibleServers(List servers, Object loadBalancerKey) {
        // loadBalancerKey = "default"
        if (loadBalancerKey == null) {
            return ImmutableList.copyOf(Iterables.filter(servers, this.getServerOnlyPredicate()));            
        } else {
            List results = Lists.newArrayList();
            for (Server server: servers) {
                // 
                if (this.apply(new PredicateKey(loadBalancerKey, server))) {
                    results.add(server);
                }
            }
            return results;            
        }
    }


    com.netflix.loadbalancer.CompositePredicate#apply
   

@Override
    public boolean apply(@Nullable PredicateKey input) {
        return delegate.apply(input);
    }

    com.netflix.loadbalancer.CompositePredicate.Builder#Builder(com.netflix.loadbalancer.AbstractServerPredicate...)
       

Builder(AbstractServerPredicate ...primaryPredicates) {
        toBuild = new CompositePredicate();
        Predicate chain = Predicates.and(primaryPredicates);
        toBuild.delegate =  AbstractServerPredicate.ofKeyPredicate(chain);                
    }

    -->com.netflix.loadbalancer.ZoneAvoidanceRule#ZoneAvoidanceRule
   

 public ZoneAvoidanceRule() {
        super();
        ZoneAvoidancePredicate zonePredicate = new ZoneAvoidancePredicate(this);
        AvailabilityPredicate availabilityPredicate = new AvailabilityPredicate(this);
        compositePredicate = createCompositePredicate(zonePredicate, availabilityPredicate);
    }

    com.netflix.loadbalancer.AbstractServerPredicate#ofKeyPredicate
     

public static AbstractServerPredicate ofKeyPredicate(final Predicate p) {
        return new AbstractServerPredicate() {
            @Override
            @edu.umd.cs.findbugs.annotations.SuppressWarnings(value = "NP")
            public boolean apply(PredicateKey input) {
                return p.apply(input);
            }            
        };        
    }

    com.netflix.loadbalancer.ZoneAvoidancePredicate#apply
   

public boolean apply(@Nullable PredicateKey input) {
        // ENABLE 默认true
        if (!ENABLED.get()) {
            return true;
        }
        // zone=UNKONWN
        String serverZone = input.getServer().getZone();
        if (serverZone == null) {
            // there is no zone information from the server, we do not want to filter
            // out this server
            return true;
        }
        LoadBalancerStats lbStats = getLBStats();
        if (lbStats == null) {
            // no stats available, do not filter
            return true;
        }
        // lbStats.getAbailableZones() = ["unknown"]
        if (lbStats.getAvailableZones().size() <= 1) {
            // only one zone is available, do not filter
            return true;
        }
        //--------------------------应该不会走到这里
        Map zoneSnapshot = ZoneAvoidanceRule.createSnapshot(lbStats);
        if (!zoneSnapshot.keySet().contains(serverZone)) {
            // The server zone is unknown to the load balancer, do not filter it out 
            return true;
        }
        logger.debug("Zone snapshots: {}", zoneSnapshot);
        Set availableZones = ZoneAvoidanceRule.getAvailableZones(zoneSnapshot, triggeringLoad.get(), triggeringBlackoutPercentage.get());
        logger.debug("Available zones: {}", availableZones);
        if (availableZones != null) {
            return availableZones.contains(input.getServer().getZone());
        } else {
            return false;
        }
    }    


    com.netflix.loadbalancer.AvailabilityPredicate#apply
     

 public boolean apply(@Nullable PredicateKey input) {
        LoadBalancerStats stats = getLBStats();
        if (stats == null) {
            return true;
        }
        // shouldSkipServer() = false
        return !shouldSkipServer(stats.getSingleServerStat(input.getServer()));
    }


    
    
   

 private boolean shouldSkipServer(ServerStats stats) {        
        if ((CIRCUIT_BREAKER_FILTERING.get() && stats.isCircuitBreakerTripped()) 
                || stats.getActiveRequestsCount() >= activeConnectionsLimit.get()) {
            return true;
        }
        return false;
    }


    继续看
   

 public Optional chooseRoundRobinAfterFiltering(List servers, Object loadBalancerKey) {
        List eligible = getEligibleServers(servers, loadBalancerKey);
        if (eligible.size() == 0) {
            return Optional.absent();
        }
        return Optional.of(eligible.get(incrementAndGetModulo(eligible.size())));
    }


   

private int incrementAndGetModulo(int modulo) {
        for (;;) {
            int current = nextIndex.get();
            int next = (current + 1) % modulo;
            if (nextIndex.compareAndSet(current, next) && current < modulo)
                return current;
        }
    }

    实现了轮询


    --------------
    接下来ping

   

  public DynamicServerListLoadBalancer(IClientConfig clientConfig, IRule rule, IPing ping,
                                         ServerList serverList, ServerListFilter 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);
    }


    super() --> com.netflix.loadbalancer.BaseLoadBalancer#BaseLoadBalancer(com.netflix.client.config.IClientConfig, com.netflix.loadbalancer.IRule, com.netflix.loadbalancer.IPing)

   

public BaseLoadBalancer(IClientConfig config, IRule rule, IPing ping) {
        initWithConfig(config, rule, ping, createLoadBalancerStatsFromConfig(config));
    }


   

 void initWithConfig(IClientConfig clientConfig, IRule rule, IPing ping, LoadBalancerStats stats) {
        this.config = clientConfig;
        String clientName = clientConfig.getClientName();
        this.name = clientName;
        // ping 周期,默认30s
        int pingIntervalTime = Integer.parseInt(""
                + clientConfig.getProperty(
                        CommonClientConfigKey.NFLoadBalancerPingInterval,
                        Integer.parseInt("30")));
        // 
        int maxTotalPingTime = Integer.parseInt(""
                + clientConfig.getProperty(
                        CommonClientConfigKey.NFLoadBalancerMaxTotalPingTime,
                        Integer.parseInt("2")));

        setPingInterval(pingIntervalTime);
        setMaxTotalPingTime(maxTotalPingTime);

        // cross associate with each other
        // i.e. Rule,Ping meet your container LB
        // LB, these are your Ping and Rule guys ...
        setRule(rule);
        setPing(ping);

        setLoadBalancerStats(stats);
        rule.setLoadBalancer(this);
        if (ping instanceof AbstractLoadBalancerPing) {
            ((AbstractLoadBalancerPing) ping).setLoadBalancer(this);
        }
        logger.info("Client: {} instantiated a LoadBalancer: {}", name, this);
        boolean enablePrimeConnections = clientConfig.get(
                CommonClientConfigKey.EnablePrimeConnections, DefaultClientConfigImpl.DEFAULT_ENABLE_PRIME_CONNECTIONS);

        if (enablePrimeConnections) {
            this.setEnablePrimingConnections(true);
            PrimeConnections primeConnections = new PrimeConnections(
                    this.getName(), clientConfig);
            this.setPrimeConnections(primeConnections);
        }
        init();

    }

     

public void setPing(IPing ping) {
        if (ping != null) {
            if (!ping.equals(this.ping)) {
                this.ping = ping;
                setupPingTask(); // since ping data changed
            }
        } else {
            this.ping = null;
            // cancel the timer task
            lbTimer.cancel();
        }
    }

   

void setupPingTask() {
        // 默认ping, 返回true
        if (canSkipPing()) {
            return;
        }
        if (lbTimer != null) {
            lbTimer.cancel();
        }
        lbTimer = new ShutdownEnabledTimer("NFLoadBalancer-PingTimer-" + name,
                true);
        lbTimer.schedule(new PingTask(), 0, pingIntervalSeconds * 1000);
        forceQuickPing();
    }


    到这里,已经执行完getServer(),server已经是一个具体的服务实例了

public  T execute(String serviceId, LoadBalancerRequest request, Object hint)
            throws IOException {
        ILoadBalancer loadBalancer = getLoadBalancer(serviceId);
        Server server = getServer(loadBalancer, hint);
        if (server == null) {
            throw new IllegalStateException("No instances available for " + serviceId);
        }
        RibbonServer ribbonServer = new RibbonServer(serviceId, server,
                isSecure(server, serviceId),
                serverIntrospector(serviceId).getMetadata(server));

        return execute(serviceId, ribbonServer, request);
    }


    

private ServerIntrospector serverIntrospector(String serviceId) {
        ServerIntrospector serverIntrospector = this.clientFactory.getInstance(serviceId,
                ServerIntrospector.class);
        if (serverIntrospector == null) {
            serverIntrospector = new DefaultServerIntrospector();
        }
        return serverIntrospector;
    }

    private boolean isSecure(Server server, String serviceId) {
        IClientConfig config = this.clientFactory.getClientConfig(serviceId);
        ServerIntrospector serverIntrospector = serverIntrospector(serviceId);
        return RibbonUtils.isSecure(config, serverIntrospector, server);
    }


    isSecure()其实是从服务实例instance里面的meta中读取
    这里用的是nacos --> NacosServerIntrospector
    com.alibaba.cloud.nacos.ribbon.NacosServerIntrospector
    

public class NacosServerIntrospector extends DefaultServerIntrospector {

    @Override
    public Map getMetadata(Server server) {
        if (server instanceof NacosServer) {
            return ((NacosServer) server).getMetadata();
        }
        return super.getMetadata(server);
    }

    @Override
    public boolean isSecure(Server server) {
        if (server instanceof NacosServer) {
            return Boolean.valueOf(((NacosServer) server).getMetadata().get("secure"));
        }

        return super.isSecure(server);
    }

}

但是request已经变化了,成了ServiceRequestWrapper,回到拦截器处理的地方
org.springframework.cloud.client.loadbalancer.LoadBalancerInterceptor#intercept

public ClientHttpResponse intercept(final HttpRequest request, final byte[] body,
            final ClientHttpRequestExecution execution) throws IOException {
        final URI originalUri = request.getURI();
        String serviceName = originalUri.getHost();
        Assert.state(serviceName != null,
                "Request URI does not contain a valid hostname: " + originalUri);
        return this.loadBalancer.execute(serviceName,
                this.requestFactory.createRequest(request, body, execution));
    }


rquestFactory是LoadBalancerInterceptor构造函数传进来的
org.springframework.cloud.client.loadbalancer.LoadBalancerAutoConfiguration#loadBalancerRequestFactory

@Bean
    @ConditionalOnMissingBean
    public LoadBalancerRequestFactory loadBalancerRequestFactory(
            LoadBalancerClient loadBalancerClient) {
        return new LoadBalancerRequestFactory(loadBalancerClient, this.transformers);
    }

org.springframework.cloud.client.loadbalancer.LoadBalancerRequestFactory#createRequest
    

public LoadBalancerRequest createRequest(
            final HttpRequest request, final byte[] body,
            final ClientHttpRequestExecution execution) {
        return instance -> {
            HttpRequest serviceRequest = new ServiceRequestWrapper(request, instance,
                    this.loadBalancer);
            if (this.transformers != null) {
                for (LoadBalancerRequestTransformer transformer : this.transformers) {
                    serviceRequest = transformer.transformRequest(serviceRequest,
                            instance);
                }
            }
            return execution.execute(serviceRequest, body);
        };
    }

execution是:org.springframework.http.client.InterceptingClientHttpRequest.InterceptingRequestExecution

public  T execute(String serviceId, ServiceInstance serviceInstance,
            LoadBalancerRequest request) throws IOException {
        Server server = null;
        if (serviceInstance instanceof RibbonServer) {
            server = ((RibbonServer) serviceInstance).getServer();
        }
        if (server == null) {
            throw new IllegalStateException("No instances available for " + serviceId);
        }

        RibbonLoadBalancerContext context = this.clientFactory
                .getLoadBalancerContext(serviceId);
        RibbonStatsRecorder statsRecorder = new RibbonStatsRecorder(context, server);

        try {
            // request --> InterceptingClientHttpRequest
            T returnVal = request.apply(serviceInstance);
            statsRecorder.recordStats(returnVal);
            return returnVal;
        }
        // catch IOException and rethrow so RestTemplate behaves correctly
        catch (IOException ex) {
            statsRecorder.recordStats(ex);
            throw ex;
        }
        catch (Exception ex) {
            statsRecorder.recordStats(ex);
            ReflectionUtils.rethrowRuntimeException(ex);
        }
        return null;
    }

request.apply()--->LoadBalancerRequestFactory#createRequest()
-->

return instance -> {
            HttpRequest serviceRequest = new ServiceRequestWrapper(request, instance,
                    this.loadBalancer);
            if (this.transformers != null) {
                for (LoadBalancerRequestTransformer transformer : this.transformers) {
                    serviceRequest = transformer.transformRequest(serviceRequest,
                            instance);
                }
            }
            return execution.execute(serviceRequest, body);
        };

--> execution.execute()
org.springframework.http.client.InterceptingClientHttpRequest.InterceptingRequestExecution#execute

@Override
        public ClientHttpResponse execute(HttpRequest request, byte[] body) throws IOException {
            // 默认iterator里面就1个LoadBalancerInterceptor
            // 并且这个方法在之前就执行过一次,
            // iterator.hasNext() = false
            if (this.iterator.hasNext()) {
                ClientHttpRequestInterceptor nextInterceptor = this.iterator.next();
                return nextInterceptor.intercept(request, body, this);
            }
            else {
                HttpMethod method = request.getMethod();
                Assert.state(method != null, "No standard HTTP method");
                // request-->ServiceRequestWrapper
                ClientHttpRequest delegate = requestFactory.createRequest(request.getURI(), method);
                request.getHeaders().forEach((key, value) -> delegate.getHeaders().addAll(key, value));
                if (body.length > 0) {
                    if (delegate instanceof StreamingHttpOutputMessage) {
                        StreamingHttpOutputMessage streamingOutputMessage = (StreamingHttpOutputMessage) delegate;
                        streamingOutputMessage.setBody(outputStream -> StreamUtils.copy(body, outputStream));
                    }
                    else {
                        StreamUtils.copy(body, delegate.getBody());
                    }
                }
                return delegate.execute();
            }
        }

        org.springframework.cloud.client.loadbalancer.ServiceRequestWrapper#getURI
        

@Override
    public URI getURI() {
        // loadBalancer --> RibbonLoadBalancerClient
        URI uri = this.loadBalancer.reconstructURI(this.instance, getRequest().getURI());
        return uri;
    }

    org.springframework.cloud.netflix.ribbon.RibbonLoadBalancerClient#reconstructURI
    

@Override
    public URI reconstructURI(ServiceInstance instance, URI original) {
        Assert.notNull(instance, "instance can not be null");
        String serviceId = instance.getServiceId();
        RibbonLoadBalancerContext context = this.clientFactory
                .getLoadBalancerContext(serviceId);

        URI uri;
        Server server;
        // instance instanceof RibbonServer == true
        if (instance instanceof RibbonServer) {
            RibbonServer ribbonServer = (RibbonServer) instance;
            server = ribbonServer.getServer();
            uri = updateToSecureConnectionIfNeeded(original, ribbonServer);
        }
        else {
            server = new Server(instance.getScheme(), instance.getHost(),
                    instance.getPort());
            IClientConfig clientConfig = clientFactory.getClientConfig(serviceId);
            ServerIntrospector serverIntrospector = serverIntrospector(serviceId);
            uri = updateToSecureConnectionIfNeeded(original, clientConfig,
                    serverIntrospector, server);
        }
        return context.reconstructURIWithServer(server, uri);
    }


com.netflix.loadbalancer.LoadBalancerContext#reconstructURIWithServer

public URI reconstructURIWithServer(Server server, URI original) {
        String host = server.getHost();
        int port = server.getPort();
        // http/https
        String scheme = server.getScheme();
        //
        if (host.equals(original.getHost()) 
                && port == original.getPort()
                && scheme == original.getScheme()) {
            return original;
        }
        if (scheme == null) {
            scheme = original.getScheme();
        }
        if (scheme == null) {
            scheme = deriveSchemeAndPortFromPartialUri(original).first();
        }

        try {
            StringBuilder sb = new StringBuilder();
            sb.append(scheme).append("://");
            if (!Strings.isNullOrEmpty(original.getRawUserInfo())) {
                sb.append(original.getRawUserInfo()).append("@");
            }
            sb.append(host);
            if (port >= 0) {
                sb.append(":").append(port);
            }
            sb.append(original.getRawPath());
            if (!Strings.isNullOrEmpty(original.getRawQuery())) {
                sb.append("?").append(original.getRawQuery());
            }
            if (!Strings.isNullOrEmpty(original.getRawFragment())) {
                sb.append("#").append(original.getRawFragment());
            }
            URI newURI = new URI(sb.toString());
            return newURI;            
        } catch (URISyntaxException e) {
            throw new RuntimeException(e);
        }
    }

    到这里就完成了服务名到ip地址的转换。
    这里execution会执行两次,这个需要特别注意一下。

nacos 的源码分析请参考文章:https://blog.csdn.net/zxh240651200/category_11544733.html

小结:

loadBalance体系,通过nacos的api获取服务列表,维持在本地里;然后通过serverlistUpater去定时更新一下服务实例列表,默认是30s。

你可能感兴趣的:(spring,cloud,负载均衡,restful,spring)