Spring中的RestTemplate源码分析

之前有一篇文章是分析的Feign, 这边文章来分析Spring中的RestTemplate,下面还会有一篇来分析最新的WebClient,当然这时后话,下面来具体看一下RestTemplate的执行流程。

Get请求流程分析(getForObject)

首先从get方法开始,传入url,返回类型,参数即可,方法原型:

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

看到他先创建了一个RequestCallback类型变量,那么这个是什么呢?

RequestCallback是一个功能接口(FunctionalInterface),里面只有一个方法声明:

void doWithRequest(ClientHttpRequest request) throws IOException;

它是用来操作request的,在请求发送前,为请求添加header,将请求体写入request。

它有两个实现类,一个是AcceptHeaderRequestCallback 实现RequestCalback,为请求添加请求头;另一个是HttpEntityRequestCallback,继承自AcceptHeaderRequestCallback ,为请求添加请求头,写入请求体。对于GET请求它使用的是AcceptHeaderRequestCallback ,即只需要处理请求头,因为GET请求并没有请求体。

新建完RequestCallback后又新建了HttpMessageConverterExtractor<T>类型变量,这个主要是从Response中获取并转换返回对象用的,后面会说到。

然后进入下一步execute方法:

	public <T> T execute(String url, HttpMethod method, @Nullable RequestCallback requestCallback,
			@Nullable ResponseExtractor<T> responseExtractor, Map<String, ?> uriVariables)
			throws RestClientException {

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

在这里它只作了一个工作,根据urlVariables中的键值对,替换url中的占位符,并转换为URI对象,然后进入方法doExecute,这一步是它的核心逻辑所在:

	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) {
			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();
			}
		}
	}

首先根据url和method参数创建Request对象,跟进方法查看:

	protected ClientHttpRequest createRequest(URI url, HttpMethod method) throws IOException {
		ClientHttpRequest request = getRequestFactory().createRequest(url, method);
		// 这个initialize也是用来设置Request,默认什么操作都没有
		initialize(request);
		if (logger.isDebugEnabled()) {
			logger.debug("HTTP " + method.name() + " " + url);
		}
		return request;
	}

可以看到它是调用了RequestFactory来创建Request对象,而RequestFactory这个属性有一个默认值,属性签名如下:

private ClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory()

进入它的createRequest方法:

	public ClientHttpRequest createRequest(URI uri, HttpMethod httpMethod) throws IOException {
		HttpURLConnection connection = openConnection(uri.toURL(), this.proxy);
		prepareConnection(connection, httpMethod.name());

		if (this.bufferRequestBody) {
			return new SimpleBufferingClientHttpRequest(connection, this.outputStreaming);
		}
		else {
			return new SimpleStreamingClientHttpRequest(connection, this.chunkSize, this.outputStreaming);
		}
	}

可以看到它是用了JDK中的HttpUrlConnection来建立连接,获取返回值,而Request对象类型根据是否缓存ReqeustBody分为SimpleBufferingClientHttpRequestSimpleStreamingClientHttpRequest两种类型,默认bufferRequestBody==true,即默认Request类型为SimpleBufferingClientHttpRequest

回到上一步,在创建完请求后,在发送请求之前还需要设置请求头和请求体,即应用RequestCallback,然后调用execute方法,这里即调用HttpUrlConnection来执行请求,它会返回一个SimpleClientHttpResponse类型对象,接下来就需要处理这个返回值。

对于这个Response,首先是调用handleResponse方法来判断请求是否有异常(根据状态码来判断):

	protected void handleResponse(URI url, HttpMethod method, ClientHttpResponse response) throws IOException {
		ResponseErrorHandler errorHandler = getErrorHandler();
		boolean hasError = errorHandler.hasError(response);
		if (logger.isDebugEnabled()) {
			try {
				int code = response.getRawStatusCode();
				HttpStatus status = HttpStatus.resolve(code);
				logger.debug("Response " + (status != null ? status : code));
			}
			catch (IOException ex) {
				// ignore
			}
		}
		if (hasError) {
			errorHandler.handleError(url, method, response);
		}
	}

如果有异常则调用errorHandler来处理,默认errorHandler类型为DefaultResponseErrorHandler,它的处理方法是抛出异常,如果这里抛出异常则执行流程结束,不会再解析返回值。

如果没有异常则调用responseExtractor来抽取返回值或者响应头(header),对于GET方法,默认的responseExtractor类型是HttpMessageConverterExtractor,它会转换response对象为指定的返回类型T,之后返回这个转换后的对象出去即可以。

getForEntity

上面讲的是getForObject方法,那么getForEntity方法呢,其实他们的区别就是传入的ResponseExtractor类型不同,getForObject传入的是HttpMessageConverterExtractor<T>, 而getForEntity传入的是ResponseExtractor<ResponseEntity<T>>,而这个ResponseExtractor<ResponseEntity<T>>只是在HttpMessageConverterExtractor上封装了一个转换操作,构造方法如下:

		public ResponseEntityResponseExtractor(@Nullable Type responseType) {
			if (responseType != null && Void.class != responseType) {
				this.delegate = new HttpMessageConverterExtractor<>(responseType, getMessageConverters(), logger);
			}
			else {
				this.delegate = null;
			}
		}

extractData方法里可以看到也只是把返回值T包装在了ResponseEntity对象里:

		public ResponseEntity<T> extractData(ClientHttpResponse response) throws IOException {
			if (this.delegate != null) {
				T body = this.delegate.extractData(response);
				return ResponseEntity.status(response.getRawStatusCode()).headers(response.getHeaders()).body(body);
			}
			else {
				return ResponseEntity.status(response.getRawStatusCode()).headers(response.getHeaders()).build();
			}
		}
	}

Post请求?

那么post方法呢?以postForObject为例:

	public <T> T postForObject(String url, @Nullable Object request, Class<T> responseType,
			Map<String, ?> uriVariables) throws RestClientException {

		RequestCallback requestCallback = httpEntityCallback(request, responseType);
		HttpMessageConverterExtractor<T> responseExtractor =
				new HttpMessageConverterExtractor<>(responseType, getMessageConverters(), logger);
		return execute(url, HttpMethod.POST, requestCallback, responseExtractor, uriVariables);
	}

它和get的主要区别就是RequestCallback实际使用的类型是HttpEntityRequestCallback,即写入请求头也写入请求体,其他并无二致。

其他

RestTemplate类图:
在这里插入图片描述
Get请求的活动图:
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/adolph09/article/details/105939847