RestTemplate使用不当引发的问题分析 (3)

此抽象类在AbstractClientHttpRequest基础之上添加了缓冲功能,可以保存要发送给服务器的数据,然后一块发送。看这一句:

ClientHttpResponse result = executeInternal(headers, bytes);

也是一个executeInternal方法,不过参数不同,它也是一个抽象方法。进入方法,到达org.springframework.http.client.InterceptingClientHttpRequest

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

实例化了一个带拦截器的请求执行对象InterceptingRequestExecution,进入看一看。

public ClientHttpResponse execute(HttpRequest request, final byte[] body) throws IOException { // 如果有拦截器,则执行拦截器并返回结果 if (this.iterator.hasNext()) { ClientHttpRequestInterceptor nextInterceptor = this.iterator.next(); return nextInterceptor.intercept(request, body, this); } else { // 如果没有拦截器,则通过requestFactory创建request对象并执行 ClientHttpRequest delegate = requestFactory.createRequest(request.getURI(), request.getMethod()); for (Map.Entry<String, List<String>> entry : request.getHeaders().entrySet()) { List<String> values = entry.getValue(); for (String value : values) { delegate.getHeaders().add(entry.getKey(), value); } } if (body.length > 0) { if (delegate instanceof StreamingHttpOutputMessage) { StreamingHttpOutputMessage streamingOutputMessage = (StreamingHttpOutputMessage) delegate; streamingOutputMessage.setBody(new StreamingHttpOutputMessage.Body() { @Override public void writeTo(final OutputStream outputStream) throws IOException { StreamUtils.copy(body, outputStream); } }); } else { StreamUtils.copy(body, delegate.getBody()); } } return delegate.execute(); } }

看一下RestTemplate的配置:

RestTemplateBuilder builder = new RestTemplateBuilder(); return builder .setConnectTimeout(customConfig.getRest().getConnectTimeOut()) .setReadTimeout(customConfig.getRest().getReadTimeout()) .interceptors(restTemplateLogInterceptor) .errorHandler(new ThrowErrorHandler()) .build(); }

可以看到配置了连接超时,读超时,拦截器,和错误处理器。
看一下拦截器的实现:

public ClientHttpResponse intercept(HttpRequest httpRequest, byte[] bytes, ClientHttpRequestExecution clientHttpRequestExecution) throws IOException { // 打印访问前日志 ClientHttpResponse execute = clientHttpRequestExecution.execute(httpRequest, bytes); if (如果返回码不是200) { // 抛出自定义运行时异常 } // 打印访问后日志 return execute; }

可以看到当返回码不是200时,抛出异常。还记得RestTemplate中的doExecute方法吧,此处如果抛出异常,虽然会执行doExecute方法中的finally代码,但由于返回的response为null(其实是有response的),没有关闭response,所以这里不能抛出异常,如果确实想抛出异常,可以在错误处理器errorHandler中抛出,这样确保response能正常返回和关闭。

RestTemplate源码部分解析 如何决定使用哪一个底层http框架

知道了原因,我们再来看一下RestTemplate在什么时候决定使用什么http框架。其实在通过RestTemplateBuilder实例化RestTemplate对象时就决定了。
看一下RestTemplateBuilder的build方法

public RestTemplate build() { return build(RestTemplate.class); } public <T extends RestTemplate> T build(Class<T> restTemplateClass) { return configure(BeanUtils.instantiate(restTemplateClass)); }

可以看到在实例化RestTemplate对象之后,进行配置。

public <T extends RestTemplate> T configure(T restTemplate) { // 配置requestFactory configureRequestFactory(restTemplate); // 配置消息转换器 if (!CollectionUtils.isEmpty(this.messageConverters)) { restTemplate.setMessageConverters( new ArrayList<HttpMessageConverter<?>>(this.messageConverters)); } //配置uri模板处理器 if (this.uriTemplateHandler != null) { restTemplate.setUriTemplateHandler(this.uriTemplateHandler); } //配置错误处理器 if (this.errorHandler != null) { restTemplate.setErrorHandler(this.errorHandler); } // 设置根路径(一般为'http://www.likecs.com/') if (this.rootUri != null) { RootUriTemplateHandler.addTo(restTemplate, this.rootUri); } // 配置登录验证 if (this.basicAuthorization != null) { restTemplate.getInterceptors().add(this.basicAuthorization); } //配置自定义restTemplate器 if (!CollectionUtils.isEmpty(this.restTemplateCustomizers)) { for (RestTemplateCustomizer customizer : this.restTemplateCustomizers) { customizer.customize(restTemplate); } } //配置拦截器 restTemplate.getInterceptors().addAll(this.interceptors); return restTemplate; }

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpdyzs.html