Ribbon(1)--->RestTemplate使用与原理分析

1、RestTemplate 是什么?有何作用?使用场景?

      RestTemplate 是spring-web 对rest规范的一个封装;它的作用就是:可以发起rest规范的请求;使用场景:凡是你在代码中需要发起http请求的地方都能使用。

2、RestTemplate的使用案例:

RestTemplate restTemplate = new RestTemplate();
ResponseEntity<OrderDto> forEntity = restTemplate.getForEntity("http://localhost:8080/getOrderById?orderId=" + orderId, OrderDto.class);

  这是一个简单的get请求的案例,RestTemplate里面封装了rest规范的所有发起请求的方式,此处我们不在一 一列举,因为我们不是偏向使用,我们主要是来分析RestTemplate的原理的。

 

3、废话不多说,源码分析开始:

     3.1、先看类图关系:

                                    

                         实现父类如下:  

                                   RestOperations : 顾名思义,这个接口就是定义了rest规范的操作集。

                                   HttpAccessor:http存储器,这个听起来是不是很奇怪,之所以叫存储器,那是因为HttpAccessor这个类能够创建Http请求实例ClientHttpRequest出来,所以就叫Http存储器。     

                                   InterceptingHttpAccessor : 拦截器存储器,里面存放的是http请求的拦截器列表。

 

      3.2、HttpAccessorhttp存储器源码分析:作用使用其成员属性ClientHttpRequestFactory requestFactory创建客户端http请求实例ClientHttpRequest

public abstract class HttpAccessor {

	protected final Log logger = HttpLogging.forLogName(getClass());

    客户端请求工厂,用于创建客户端http请求实例ClientHttpRequest,默认是SimpleClientHttpRequestFactory,可以进行替换,例如切换为apache httpclient、okhttp都可以。
	private ClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();

    客户端http请求初始者列表,用于初始化创建好的客户端http请求。
	private final List<ClientHttpRequestInitializer> clientHttpRequestInitializers = new ArrayList<>();


	public void setRequestFactory(ClientHttpRequestFactory requestFactory) {
		Assert.notNull(requestFactory, "ClientHttpRequestFactory must not be null");
		this.requestFactory = requestFactory;
	}


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


	public void setClientHttpRequestInitializers(
			List<ClientHttpRequestInitializer> clientHttpRequestInitializers) {

		if (this.clientHttpRequestInitializers != clientHttpRequestInitializers) {
			this.clientHttpRequestInitializers.clear();
			this.clientHttpRequestInitializers.addAll(clientHttpRequestInitializers);
			AnnotationAwareOrderComparator.sort(this.clientHttpRequestInitializers);
		}
	}


	public List<ClientHttpRequestInitializer> getClientHttpRequestInitializers() {
		return this.clientHttpRequestInitializers;
	}


    创建客户端http请求且使用初始化者进行初始化
	protected ClientHttpRequest createRequest(URI url, HttpMethod method) throws IOException {
		ClientHttpRequest request = getRequestFactory().createRequest(url, method);
		initialize(request);
		if (logger.isDebugEnabled()) {
			logger.debug("HTTP " + method.name() + " " + url);
		}
		return request;
	}

	private void initialize(ClientHttpRequest request) {
		this.clientHttpRequestInitializers.forEach(initializer -> initializer.initialize(request));
	}

}

             ClientHttpRequestFactory接口类图:

                     

                     在上面类图中我们没有对RibbonClientHttpRequestFactory进行说明,原因是RibbonClientHttpRequestFactory 这个客户端请求工厂它是使用了Netflix的RestClient来进行http请求的发起与响应的处理的,其底层处理http请求与响应的http客户端是jersey。

                     InterceptingClientHttpRequestFactory只是一个包装了ClientHttpRequestFactory + interceptors的包装器。

                     我们知道了ClientHttpRequestFactory是用来创建客户端http请求实例的ClientHttpRequest,其实ClientHttpRequest也是一个接口,接下来我们看看ClientHttpRequest的接口类图:

                                   

                       每一种ClientHttpRequestFactory创建的客户端请求实例类型关系:

                                   SimpleClientHttpRequestFactory------------> SimpleBufferingClientHttpRequest(HttpURLConnection connection, boolean outputStreaming)

                                   HttpComponentsClientHttpRequestFactory--------> HttpComponentsClientHttpRequest(HttpClient client, HttpUriRequest request, HttpContext context)

                                   OkHttp3ClientHttpRequestFactory--------------> OkHttp3ClientHttpRequest(OkHttpClient client, URI uri, HttpMethod method)

                                   RibbonClientHttpRequestFactory---------> RibbonHttpRequest(URI uri, HttpRequest.Verb verb, RestClient client, IClientConfig config)

                                   InterceptingClientHttpRequestFactory--------> InterceptingClientHttpRequest(ClientHttpRequestFactory chrf, List<ClientHttpRequestInterceptor> interceptors, URI uri, HttpMethod method)

 

 

     3.3、InterceptingHttpAccessor拦截器储存器源码分析

public abstract class InterceptingHttpAccessor extends HttpAccessor {

    储存的拦截器,这些拦截器会在http请求被执行之前进行调用
	private final List<ClientHttpRequestInterceptor> interceptors = new ArrayList<>();

    看见没这里立马就使用了有拦截功能的请求工厂,就是我们上面提到的InterceptingClientHttpRequestFactory
	@Nullable
	private volatile ClientHttpRequestFactory interceptingRequestFactory;

    public级别的方法,因此可以设置拦截器列表
	public void setInterceptors(List<ClientHttpRequestInterceptor> interceptors) {
		Assert.noNullElements(interceptors, "'interceptors' must not contain null elements");
		// Take getInterceptors() List as-is when passed in here
		if (this.interceptors != interceptors) {
			this.interceptors.clear();
			this.interceptors.addAll(interceptors);
			AnnotationAwareOrderComparator.sort(this.interceptors);
		}
	}


	public List<ClientHttpRequestInterceptor> getInterceptors() {
		return this.interceptors;
	}

    设置客户端http请求工厂,这里我们就能够替换掉RestTemplate底层的httpclient的类型,例如切换成okhttp3.
	@Override
	public void setRequestFactory(ClientHttpRequestFactory requestFactory) {
        调用父类的setRequestFactory方法,父类是谁,不就是HttpAccessor吗,那这样的话
        HttpAccessor中的requestFactory = 我们设置的了,不再是默认的new 
        SimpleClientHttpRequestFactory()了吧,这就起到了切换httpclient类型的效果。

		super.setRequestFactory(requestFactory);
		this.interceptingRequestFactory = null;
	}


    获取请求工厂,这个是核心方法!!!!!!!!!!!!!!!!
	@Override
	public ClientHttpRequestFactory getRequestFactory() {
        1、先获取存储的拦截器列表
		List<ClientHttpRequestInterceptor> interceptors = getInterceptors();

        2、如果有拦截器那就构建一个带拦截功能的客户端http请求工厂InterceptingClientHttpRequestFactory实例返回。
		if (!CollectionUtils.isEmpty(interceptors)) {
			ClientHttpRequestFactory factory = this.interceptingRequestFactory;
			if (factory == null) {
				factory = new InterceptingClientHttpRequestFactory(super.getRequestFactory(), interceptors);
				this.interceptingRequestFactory = factory;
			}
			return factory;
		}

        3、如果没有拦截器那就直接获取父类HttpAccessor中的客户端http请求工厂实例返回。
		else {
			return super.getRequestFactory();
		}
	}

}

 

     3.4、最终的实现类RestTemplate源码解析:

              上面我们把 RestTemplate 的父类 InterceptingHttpAccessor 以及 InterceptingHttpAccessor 的父类 HttpAccessor 进行了剖析,下面我们来剖析最终的实现类 RestTemplate;

               3.4.1、RestTemplate 的核心属性:

                        Ⅰ:    List<HttpMessageConverter<?>> messageConverters:消息转换器列表,在 springmvc 中这个应该不陌生。

                        Ⅱ: ResponseErrorHandler errorHandler = new DefaultResponseErrorHandler(); :响应错误处理器。

                        Ⅲ: ResponseExtractor<HttpHeaders> headersExtractor = new HeadersExtractor(); :响应头提取器。

                        Ⅳ:继承父类 HttpAccessor 的属性 ClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory() :http 请求构建工厂。

                       Ⅴ:继承父类 InterceptingHttpAccessor 的属性private final List<ClientHttpRequestInterceptor> interceptors = new ArrayList<>() :拦截器列表,这个是很重要的东西,在spring-cloud-netflix-ribbon中就是使用了拦截器进行负载均衡处理的。

 

                3.4.2、RestTemplate 核心属性的设置方式:

                         方式1:set函数:

             restTemplate.setErrorHandler(ResponseErrorHandler errorHandler);
             restTemplate.setMessageConverters(List<HttpMessageConverter<?>> messageConverters);
             restTemplate.setRequestFactory(ClientHttpRequestFactory requestFactory);
             restTemplate.setInterceptors(List<ClientHttpRequestInterceptor> interceptors);

                        方式2: 构造函数, 默认的无参数构造函数会自动设置一些常用的 HttpMessageConverter 列表;

             这个构造函数可以设置ClientHttpRequestFactory属性,因此可以设置为okhttp、apache httpComponentClient等客户端。
             public RestTemplate(ClientHttpRequestFactory requestFactory) {
                this();
                setRequestFactory(requestFactory);
             }

             这个构造函数可以设置入参HttpMessageConverter列表,拦截器的顺序可以使用@Order注解,或者实现Ordered接口来进行定义。
             public RestTemplate(List<HttpMessageConverter<?>> messageConverters) {
		        validateConverters(messageConverters);
		        this.messageConverters.addAll(messageConverters);
		        this.uriTemplateHandler = initUriTemplateHandler();
	         }

 

             3.4.3、RestTemplate执行流程的解析;

                         案例1:无拦截器案例

                RestTemplate restTemplate = new RestTemplate();
                ResponseEntity<OrderDto> forEntity = restTemplate.getForEntity("http://localhost:8080/getOrderById?orderId=" + orderId, OrderDto.class);

                                 第1步:RestTemplate.getForEntity(String url, Class<T> responseType, Object... uriVariables);

	                   @Override
	                   public <T> ResponseEntity<T> getForEntity(String url, Class<T> responseType, Object... uriVariables)throws RestClientException {
		                    RequestCallback requestCallback = acceptHeaderRequestCallback(responseType);
		                    ResponseExtractor<ResponseEntity<T>> responseExtractor = responseEntityExtractor(responseType);
		                    return nonNull(execute(url, HttpMethod.GET, requestCallback, responseExtractor, uriVariables));
	                   }

                                  第2步:RestTemplate.execute(String url, HttpMethod method, @Nullable RequestCallback requestCallback, @Nullable ResponseExtractor<T> responseExtractor, Object... uriVariables);

	                  @Override
	                  @Nullable
	                  public <T> T execute(String url, HttpMethod method, @Nullable RequestCallback requestCallback,@Nullable ResponseExtractor<T> responseExtractor, Object... uriVariables) throws RestClientException {
                           获取url模板处理器进行url的处理,例如GET请求的参数替换。
		                   URI expanded = getUriTemplateHandler().expand(url, uriVariables);
		                   return doExecute(expanded, method, requestCallback, responseExtractor);
	                   }

                                   第3步:RestTemplate.doExecute(URI url, @Nullable HttpMethod method, @Nullable RequestCallback requestCallback, @Nullable ResponseExtractor<T> responseExtractor);

                       @Nullable
                       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 {
                       
                            1、创建一个请求,此处就会调用父类HttpAccessor的createRequest方法。
                       		ClientHttpRequest request = createRequest(url, method);
                       		if (requestCallback != null) {
                       			requestCallback.doWithRequest(request);
                       		}
                            2、执行请求。
                       		response = request.execute();
                       
                            3、处理响应
                       		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();
                       		}
                       	}
                       }

           父类HttpAccessor的createRequest(URI url, HttpMethod method)实现:
					   	protected ClientHttpRequest createRequest(URI url, HttpMethod method) throws IOException {
						    先获取客户端http请求工厂,然后使用请求工厂创建客户端http请求实例,
在我们当前的案例中requestFactory = new SimpleClientHttpRequestFactory()的,因此创建的客户端
请求实例就是SimpleBufferingClientHttpRequest(connection, this.outputStreaming)实例,jdk的
HttpURLConnection来进行请求发送,在创建SimpleClientHttpRequestFactory的createRequest方法中会
先openConnection也就是打开连接,然后使用连接构建SimpleBufferingClientHttpRequest返回。

		                    ClientHttpRequest request = getRequestFactory().createRequest(url, method);
							
							初始化客户端http请求实例
		                    initialize(request);
		                    if (logger.isDebugEnabled()) {
			                   logger.debug("HTTP " + method.name() + " " + url);
		                    }
							
							返回客户端http请求实例
		                    return request;
	                    }

            SimpleBufferingClientHttpRequest的execute()方法实现:
               首先执行一级父类AbstractClientHttpRequest的execute()方法:
                       	@Override
	                    public final ClientHttpResponse execute() throws IOException {
		                  assertNotExecuted();

                          执行内部的执行函数
		                  ClientHttpResponse result = executeInternal(this.headers);
		                  this.executed = true;
		                  return result;
	                   }
                
               接着来到二级父类AbstractBufferingClientHttpRequestexecuteInternal(..):
                       	@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;
	                    }
                最终执行到SimpleBufferingClientHttpRequest的executeInternal(...):
                        	protected ClientHttpResponse executeInternal(HttpHeaders headers, byte[] bufferedOutput) throws IOException {
		                       addHeaders(this.connection, headers);
		                       // JDK <1.8 doesn't support getOutputStream with HTTP DELETE
		                       if (getMethod() == HttpMethod.DELETE && bufferedOutput.length == 0) {
			                      this.connection.setDoOutput(false);
		                       }
		                       if (this.connection.getDoOutput() && this.outputStreaming) {
			          this.connection.setFixedLengthStreamingMode(bufferedOutput.length);
		                       }

                               发起http请求
		                       this.connection.connect();

	                           if (this.connection.getDoOutput()) {
			                       FileCopyUtils.copy(bufferedOutput, this.connection.getOutputStream());
		                       }
		                      else {
			                    // Immediately trigger the request in a no-output scenario as well
			                    this.connection.getResponseCode();
		                      }
		                      return new SimpleClientHttpResponse(this.connection);
	                       }

             

                                                

 

                         案例2:有拦截器案例

           @Order(0)
           @Component
           public class MyClientHttpRequestInterceptor implements ClientHttpRequestInterceptor {
              @Override
              public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
                System.out.println("call MyClientHttpRequestInterceptor intercept . . .");
                execution.execute(request, body);
                return null;
              }
           }



          @Bean
          public RestTemplate restTemplate(MyClientHttpRequestInterceptor myClientHttpRequestInterceptor){
             RestTemplate restTemplate = new RestTemplate();
             List<ClientHttpRequestInterceptor> intercepters = new ArrayList <>();
             intercepters.add(myClientHttpRequestInterceptor);
             restTemplate.setInterceptors(intercepters);
             return restTemplate;
          }


         @Autowired
         private RestTemplate restTemplate;


         @GetMapping("userGetOrderById")
         public OrderDto userGetOrderById(@RequestParam("orderId") String orderId){
             ResponseEntity<OrderDto> forEntity = restTemplate.getForEntity("http://localhost:8080/getOrderById?orderId=" + orderId, OrderDto.class);
             return forEntity.getBody();
         }

                     跟没有拦截器的唯一的区别就在于RestTemplate.doExecute(URI url, @Nullable HttpMethod method, @Nullable RequestCallback requestCallback, @Nullable ResponseExtractor<T> responseExtractor)这个方法中的依据代码:ClientHttpRequest request = createRequest(url, method); 就会调用父类HttpAccessor的createRequest(URI url, HttpMethod method)方法,源码如下:

	         protected ClientHttpRequest createRequest(URI url, HttpMethod method) throws IOException {

               在当前的HttpAccessor类中有一个getRequestFactory(),然而在子类
InterceptingHttpAccessor中复写了这个方法,那么就会来到子类InterceptingHttpAccessor中
		       ClientHttpRequest request = getRequestFactory().createRequest(url, method);
		       initialize(request);
		       if (logger.isDebugEnabled()) {
			     logger.debug("HTTP " + method.name() + " " + url);
		       }
		       return request;
	        }



子类InterceptingHttpAccessor中的 getRequestFactory()实现如下:
            @Override
	        public ClientHttpRequestFactory getRequestFactory() {
		       List<ClientHttpRequestInterceptor> interceptors = getInterceptors();

               如果存在拦截器,那就构建一个InterceptingClientHttpRequestFactory类型的客户端请
           求工厂,我们都知道InterceptingClientHttpRequestFactory只是一个包装,因此会使用父类
           HttpAccessor的requestFactory来构建InterceptingClientHttpRequestFactory实例。

		       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创建的请求类型是InterceptingClientHttpRequest,InterceptingClientHttpRequestFactory源码如下:

                 public class InterceptingClientHttpRequestFactory extends AbstractClientHttpRequestFactoryWrapper {
                 
                 	private final List<ClientHttpRequestInterceptor> interceptors;
                 
                 
                 	public InterceptingClientHttpRequestFactory(ClientHttpRequestFactory requestFactory,
                 			@Nullable List<ClientHttpRequestInterceptor> interceptors) {
                 
                 		super(requestFactory);
                 		this.interceptors = (interceptors != null ? interceptors : Collections.emptyList());
                 	}
                 
                 
                    创建InterceptingClientHttpRequest请求实例
                 	@Override
                 	protected ClientHttpRequest createRequest(URI uri, HttpMethod httpMethod, ClientHttpRequestFactory requestFactory) {
                 		return new InterceptingClientHttpRequest(requestFactory, this.interceptors, uri, httpMethod);
                 	}
                 
                 }

                         InterceptingClientHttpRequest请求源码如下:

                class InterceptingClientHttpRequest extends AbstractBufferingClientHttpRequest {
                
                	private final ClientHttpRequestFactory requestFactory;
                
                	private final List<ClientHttpRequestInterceptor> interceptors;
                
                	private HttpMethod method;
                
                	private URI uri;
                
                
                	protected InterceptingClientHttpRequest(ClientHttpRequestFactory requestFactory,
                			List<ClientHttpRequestInterceptor> interceptors, URI uri, HttpMethod method) {
                
                		this.requestFactory = requestFactory;
                		this.interceptors = interceptors;
                		this.method = method;
                		this.uri = uri;
                	}
                
                
                	@Override
                	public HttpMethod getMethod() {
                		return this.method;
                	}
                
                	@Override
                	public String getMethodValue() {
                		return this.method.name();
                	}
                
                	@Override
                	public URI getURI() {
                		return this.uri;
                	}
                
                    最终执行父类的execute后会调用到此处的executeInternal方法
                	@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();
                				return nextInterceptor.intercept(request, body, this);
                			}

                            所有的拦截器执行完成后开始执行http请求的发起与处理响应
                			else {
                				HttpMethod method = request.getMethod();
                				Assert.state(method != null, "No standard HTTP method");

                                当前的拦截器请求实例InterceptingClientHttpRequest只是一个包装,因此还需要使用HttpAccessor的requestFactory来创建真正的客户端http请求实例。
                				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());
                					}
                				}

                                使用真正的客户端http请求实例发起http请求。
                				return delegate.execute();
                			}
                		}
                	}
                }

 

以上就是RestTemplate的原理剖析,之所以来剖析RestTemplate的原理,就是为了后面学习spring-cloud-netfliux-ribbon打基础。

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值