SpringCloud之Ribbon组件

在SpringCloud让RestTemplate支持负载均衡和服务发现功能,只需如下写法:

    @Bean
    @LoadBalanced
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }

加上LoadBalanced标签就可以了,这其中SpringCloud怎么做到的?

1、RestTemplate的源码分析:

public RestTemplate() {
		this.messageConverters.add(new ByteArrayHttpMessageConverter());
		this.messageConverters.add(new StringHttpMessageConverter());
		this.messageConverters.add(new ResourceHttpMessageConverter(false));
                ...      
	}

看RestTemplate的构造函数只是配置了消息转换器,我们重点挑getForEntity看:

protected <T> T doExecute(URI url, @Nullable HttpMethod method, @Nullable RequestCallback requestCallback,
			@Nullable ResponseExtractor<T> 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);
			}
			response = request.execute();//真正执行请求
			handleResponse(url, method, response);
			return (responseExtractor != null ? responseExtractor.extractData(response) : null);
		}
		catch (IOException ex) {
		}
		finally {
		}
	}

 上面我们主要看createRequest和execute两个地方,先来看createRequest方法:

	protected ClientHttpRequest createRequest(URI url, HttpMethod method) throws IOException {
		ClientHttpRequest request = getRequestFactory().createRequest(url, method);
		if (logger.isDebugEnabled()) {
			logger.debug("HTTP " + method.name() + " " + url);
		}
		return request;
	}

 这里最主要的是getRequestFactory方法,获取Request的工厂,继续往下看:

public ClientHttpRequestFactory getRequestFactory() {
		List<ClientHttpRequestInterceptor> 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();
		}
	}

 从上面我们可以看到,如果有拦截器,则创建的是InterceptingClientHttpRequestFactory,没过滤器则返回默认的SimpleClientHttpRequestFactory,但是我们可以看到RestTemplate的另一构造函数:

	public RestTemplate(ClientHttpRequestFactory requestFactory) {
		this();
		setRequestFactory(requestFactory);
	}

  这里我们可以看到

RestTemplate可以支持第三方的ClientHttpRequestFactory,通过Spring官方可以看到支持如下第三方组件

 

 

 现在我们来分析第二个方法request.execute(),我们通过代码进到AbstractClientHttpRequest这个模板类中,看到如下代码:

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

 我们看到真的实现方法是子类的executeInternal,这里我们在上面分析getRequestFactory方法时就发现有两个子类:InterceptingClientHttpRequestFactory,SimpleClientHttpRequestFactory;

这里有两种情况,如果设置了拦截器走的是InterceptingClientHttpRequestFactory的executeInternal方法,没设置走的是SimpleClientHttpRequestFactory的executeInternal方法,这里我们就看InterceptingClientHttpRequestFactory这个子类的,代码如下:

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


	private class InterceptingRequestExecution implements ClientHttpRequestExecution {

		private final Iterator<ClientHttpRequestInterceptor> iterator;

		public InterceptingRequestExecution() {
			this.iterator = interceptors.iterator();
		}

		@Override
		public ClientHttpResponse execute(HttpRequest request, byte[] body) throws IOException {
                       //遍历过滤器
			if (this.iterator.hasNext()) {
				ClientHttpRequestInterceptor nextInterceptor = this.iterator.next();
                                //这里会递归调用InterceptingRequestExecution的execute方法
				return nextInterceptor.intercept(request, body, this);
			}
			else {
                                //如果没拦截器了则使用requestFactory去重新创建请求
				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();
			}
		}
	}

 这里主要是递归调用拦截器,然后通过requestFactory.createRequest()重新创建请求,调用execute()方法,这里注意的是requestFactory这个工厂拿的不是InterceptingClientHttpRequestFactory,而是默认的SimpleClientHttpRequestFactory或者你在构造函数或者setRequestFactory方法设置过的ClientHttpRequestFactory;

通过分析RestTemplate源码我们发现如果想基于这个基础上实现别的拓展功能只有在ClientHttpRequestInterceptor或者ClientHttpRequestFactory上做文章了。

2、SpringCloud中对RestTemplated的拓展:

在SpringCloud整个技术栈中有个很核心的包是:spring-cloud-commons包,这里面定义了服务注册于发现、负载均衡、熔断等通用接口,这里我们定位到org.springframework.cloud.client.loadbalancer这个包中的LoadBalancerAutoConfiguration这个配置类,我们可以发现到如下几个核心的地方:

	//这个地方注入的是带有LoadBalanced注解的RestTemplate
  @LoadBalanced
	@Autowired(required = false)
	private List<RestTemplate> restTemplates = Collections.emptyList();

	//SmartInitializingSingleton中的afterSingletonsInstantiated这个方法会在所有单例初始化完成调用
	@Bean
	public SmartInitializingSingleton loadBalancedRestTemplateInitializerDeprecated(
			final ObjectProvider<List<RestTemplateCustomizer>> restTemplateCustomizers) {
		return () -> restTemplateCustomizers.ifAvailable(customizers -> {
			for (RestTemplate restTemplate : LoadBalancerAutoConfiguration.this.restTemplates) {
				for (RestTemplateCustomizer customizer : customizers) {
					customizer.customize(restTemplate);
				}
			}
		});
	}

	//这里只是注入了添加负载均衡拦截器的方法
	@Bean
	@ConditionalOnMissingBean
	public RestTemplateCustomizer restTemplateCustomizer(
			final LoadBalancerInterceptor loadBalancerInterceptor) {
		return restTemplate -> {
			List<ClientHttpRequestInterceptor> list = new ArrayList<>(
					restTemplate.getInterceptors());
			list.add(loadBalancerInterceptor);
			restTemplate.setInterceptors(list);
		};
	}

 注入负债均衡拦截器就是靠这三步实现的,然后我们去到LoadBalancerInterceptor看如下代码:

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

 这里面就是实现负载均衡和服务发现的入口。

 

posted @ 2019-10-06 22:48  myTang  阅读(171)  评论(0)    收藏  举报