核心方法为org.springframework.web.client.RestTemplate.doExecute(URI, HttpMethod, RequestCallback, ResponseExtractor<T>)web
方法内容以下:spring
其中,重点在下面这三行:apache
ClientHttpRequest是http请求调用的抽象,具体实现有jdk自带的以及apache的httpclient,实现类以下:缓存
simple开头的是使用jdk自带的net操做,Components的底层是httpclient操做。post
AbstractBufferingClientHttpRequest为缓存requestbody的基类,内部bufferedOutput保存了requestbody的内容,避免流的二次读取会致使读取不到数据。this
那么,究竟是哪里给这个ByteArrayOutputStream对象赋值的呢?答案就在org.springframework.web.client.RestTemplate.HttpEntityRequestCallback,注释讲得很清楚:spa
在上面讲到的重点强调的三行代码中,调用了org.springframework.web.client.RestTemplate.HttpEntityRequestCallback.doWithRequest(ClientHttpRequest)方法,这个方法里面根据requestContentType等信息,在HttpMessageConverters列表中寻找合适的HttpMessageConverter,利用这些httpMessageConverter自然的write方法将requestBody的内容通过处理转换写入入参HttpOutputMessage对应的getBody方法返回的OutputStream流中。然而,咱们这里的ClientHttpRequest接口继承自HttpOutputMessage,AbstractClientHttpRequest的getBody实现调用子类的getBodyInternal方法,重点来了,AbstractBufferingClientHttpRequest的getBodyInternal返回的就是bufferedOutput,也就是缓存的ByteArrayOutputStream。到这里,缓存的requestbody数据有了。再啰嗦一句,使用HttpEntityRequestCallback的都是post请求的,get请求用的AcceptHeaderRequestCallback。rest
那么,问题来了,什么状况下会用这个缓存数据呢?咱们看下AbstractBufferingClientHttpRequest的子类就知道了。code
这里,又要回到刚刚的三行重点代码,doExecute的时候调用createRequest方法返回ClientHttpRequest,实际调用父类方法org.springframework.http.client.support.HttpAccessor.createRequest(URI, HttpMethod):对象
org.springframework.http.client.support.InterceptingHttpAccessor.getRequestFactory()方法以下:
若是设置了拦截器就返回InterceptingClientHttpRequestFactory,并将restTemplete原有的RequestFactory做为参数传入。
该factory建立的是org.springframework.http.client.InterceptingClientHttpRequest,该类重写的executeInternal方法经过内部类InterceptingRequestExecution实现interceptors顺序执行,当迭代结束后,经过以前传进来的requestFactory建立ClientHttpRequest,并将body copy给刚刚建立的request的body,并调用execute方法,方法内容以下:
其实,InterceptingClientHttpRequest自己就带有requestbody缓存copy功能,因此无需在建立restTemplate时包装一个BufferingClientHttpRequestFactory,直接使用HttpComponentsClientHttpRequestFactory便可,这个factory自带bufferRequestBody功能。
相信大部分同窗在项目中都是选择apache的httpclient发送http请求,因此,这里咱们重点看下org.springframework.http.client.HttpComponentsClientHttpRequestFactory,咱们看下createRequest方法:
public ClientHttpRequest createRequest(URI uri, HttpMethod httpMethod) throws IOException { HttpClient client = getHttpClient(); HttpUriRequest httpRequest = createHttpUriRequest(httpMethod, uri); postProcessHttpRequest(httpRequest); HttpContext context = createHttpContext(httpMethod, uri); if (context == null) { context = HttpClientContext.create(); } // Request configuration not set in the context if (context.getAttribute(HttpClientContext.REQUEST_CONFIG) == null) { // Use request configuration given by the user, when available RequestConfig config = null; if (httpRequest instanceof Configurable) { config = ((Configurable) httpRequest).getConfig(); } if (config == null) { config = createRequestConfig(client); } if (config != null) { context.setAttribute(HttpClientContext.REQUEST_CONFIG, config); } } // 默认状况下bufferRequestBody为true,建立使用缓存的body做为请求体 if (this.bufferRequestBody) { return new HttpComponentsClientHttpRequest(client, httpRequest, context); } else { return new HttpComponentsStreamingClientHttpRequest(client, httpRequest, context); } }
看下上面注释的类的下面方法org.springframework.http.client.HttpComponentsClientHttpRequest.executeInternal(HttpHeaders, byte[]):
这个类也是继承自AbstractBufferingClientHttpRequest,因此刚刚InterceptingRequestExecution迭代结束后getBody返回的就是缓存的bufferedOutput,到这里执行的时候就将bufferedOutput做为ByteArrayEntity发送http请求。至此,结束。