环境约束:html
spring-web-4.3.9.RELEASEjava
Spring文档: https://docs.spring.io/spring/docs/4.3.9.RELEASE/spring-framework-reference/html/remoting.html#rest-client-accessweb
The
RestTemplate
is the core class for client-side access to RESTful services. It is conceptually similar to other template classes in Spring, such asJdbcTemplate
andJmsTemplate
and other template classes found in other Spring portfolio projects.RestTemplate’s behavior is customized by providing callback methods and configuring the HttpMessageConverter
used to marshal objects into the HTTP request body and to unmarshal any response back into an object. As it is common to use XML as a message format, Spring provides aMarshallingHttpMessageConverter
that uses the Object-to-XML framework that is part of theorg.springframework.oxm
package. This gives you a wide range of choices of XML to Object mapping technologies to choose from.springThis section describes how to use the
RestTemplate
and its associatedHttpMessageConverters
.apache
RestTemplate
是Spring的经过客户端访问RESTful服务端的核心类,和JdbcTemplate
、JmsTemplate
概念类似,都是Spring提供的模板类RestTemplate
的行为能够经过callback回调方法和配置HttpMessageConverter
来定制,用来把对象封装到HTTP请求体,将响应信息放到一个对象中
Invoking RESTful services in Java is typically done using a helper class such as Apache HttpComponents
HttpClient
. For common REST operations this approach is too low level as shown below.jsonjava中调用RESTful服务很典型的是使用
HttpClient
,对于经常使用的REST操做,这些方法属于低等级的操做api
String uri = "http://example.com/hotels/1/bookings"; PostMethod post = new PostMethod(uri); String request = // create booking request content post.setRequestEntity(new StringRequestEntity(request)); httpClient.executeMethod(post); if (HttpStatus.SC_CREATED == post.getStatusCode()) { Header location = post.getRequestHeader("Location"); if (location != null) { System.out.println("Created new booking at :" + location.getValue()); } }
使用HttpClient
咱们须要本身封装Post请求,再根据响应的状态码判断从响应中获取header和body,有时候还须要本身作json转换数组
RestTemplate provides higher level methods that correspond to each of the six main HTTP methods that make invoking many RESTful services a one-liner and enforce REST best practices.springboot
RestTemplate提供更高等级的符合HTTP的6中主要方法,能够很简单的调用RESTful服务架构
建立RestTemplate很简单,只须要new RestTemplate()
,若是使用Spring架构,将建立的RestTemplate实例经过XML或注解的方式注册到Spring容器中便可
举例:
@Bean public RestTemplate restTemplate() { return new RestTemplate(); }
RestTemplate有3个构造方法,一个无参构造,两个有参构造
RestTemplate无参构造
/** * Create a new instance of the {@link RestTemplate} using default settings. * Default {@link HttpMessageConverter}s are initialized. * 使用默认配置建立一个RestTemplate实例 * 默认的HttpMessageConverter集合被初始化 */ public RestTemplate() { this.messageConverters.add(new ByteArrayHttpMessageConverter()); this.messageConverters.add(new StringHttpMessageConverter()); this.messageConverters.add(new ResourceHttpMessageConverter()); this.messageConverters.add(new SourceHttpMessageConverter<Source>()); this.messageConverters.add(new AllEncompassingFormHttpMessageConverter()); if (romePresent) { this.messageConverters.add(new AtomFeedHttpMessageConverter()); this.messageConverters.add(new RssChannelHttpMessageConverter()); } if (jackson2XmlPresent) { this.messageConverters.add(new MappingJackson2XmlHttpMessageConverter()); } else if (jaxb2Present) { this.messageConverters.add(new Jaxb2RootElementHttpMessageConverter()); } /** * 若是类路径下包含com.fasterxml.jackson.databind.ObjectMapper 和 com.fasterxml.jackson.core.JsonGenerator * 使用jackson作http请求、响应的json转换 */ if (jackson2Present) { this.messageConverters.add(new MappingJackson2HttpMessageConverter()); } else if (gsonPresent) { this.messageConverters.add(new GsonHttpMessageConverter()); } }
参数为ClientHttpRequestFactory的构造
/** * Create a new instance of the {@link RestTemplate} based on the given {@link ClientHttpRequestFactory}. * @param requestFactory HTTP request factory to use * @see org.springframework.http.client.SimpleClientHttpRequestFactory * @see org.springframework.http.client.HttpComponentsClientHttpRequestFactory * 使用指定的ClientHttpRequestFactory建立一个RestTemplate实例 * requestFactory是用于建立HTTP请求的工厂,默认的实现有 * SimpleClientHttpRequestFactory、HttpComponentsClientHttpRequestFactory * 若是没有设置默认是SimpleClientHttpRequestFactory */ public RestTemplate(ClientHttpRequestFactory requestFactory) { this(); //也会调用无参构造初始化默认的messageConverters setRequestFactory(requestFactory); }
参数为messageConverters的构造
/** * Create a new instance of the {@link RestTemplate} using the given list of * {@link HttpMessageConverter} to use * @param messageConverters the list of {@link HttpMessageConverter} to use * @since 3.2.7 * 传入自定义的HttpMessageConverter集合,并赋值给messageConverters,以后使用自定义的HttpMessageConverter */ public RestTemplate(List<HttpMessageConverter<?>> messageConverters) { Assert.notEmpty(messageConverters, "At least one HttpMessageConverter required"); this.messageConverters.addAll(messageConverters); }
RestTemplate 4.3.9.RELEASE版本 API
HTTP Method | RestTemplate Method |
---|---|
DELETE | void delete(String url, Object... uriVariables) void delete(String url, Map<String,?> uriVariables) void delete(URI url) |
GET |
|
HEAD | HttpHeaders headForHeaders(String url, Object... uriVariables) HttpHeaders headForHeaders(String url, Map<String,?> uriVariables) HttpHeaders headForHeaders(URI url) |
OPTIONS | Set
Set Set |
POST |
|
PUT | void put(String url, Object request, Object... uriVariables) void put(String url, Object request, Map<String,?> uriVariables) void put(URI url, Object request) |
PATCH and others | exchange()、execute() |
RestTemplate的方法名遵循必定的命名规范,第一部分表示用哪一种HTTP方法调用(get,post),第二部分表示返回类型
每一个HTTP方法对应的RestTemplate方法都有3种。其中2种的url参数为字符串,URI参数变量分别是Object数组和Map,第3种使用URI类型做为参数
注意,使用字符串类型的url默认会对url进行转义,如http://example.com/hotel list
在执行时会转义为http://example.com/hotel%20list
,这样实际上是没有问题的,但若是字符串类型的url自己已经转义过了,执行时就会再转义一次,变成http://example.com/hotel%2520list
。若是不须要这种隐式的转义,可使用java.net.URI
参数的方法,这种方法不会在执行时存在隐式的url转义,能够在建立URI
对象时自行决定是否转义,推荐使用UriComponentsBuilder
建立URI
UriComponents uriComponents = UriComponentsBuilder.fromUriString( "http://example.com/hotels/{hotel}/bookings/{booking}") .build() //build(true)就不会对url转义,但若是包含http://example.com/hotel list这种须要转义的url,会报错 .expand("42", "21") .encode(); URI uri = uriComponents.toUri();
exchange
和execute
方法比上面列出的其它方法(如getForObject、postForEntity等)使用范围更广,容许调用者指定HTTP请求的方法(GET、POST、PUT等),而且能够支持像HTTP PATCH(部分更新),但须要底层的HTTP库支持,JDK自带的HttpURLConnection
不支持PATCH方法,Apache的HTTPClient 4.2及之后版本支持
发送GET请求,返回ResponseEntity
/** * 参数1: String类型 或 URI类型的请求地址 * 参数2: 指定返回的实体类型,class对象 * 参数3: uri参数,能够是变长数组或map * 返回值:ResponseEntity<T>是Spring对HTTP响应的封装,包括了几个重要的元素,如响应码、contentType、contentLength、response header信息,response body信息等 */ @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 execute(url, HttpMethod.GET, requestCallback, responseExtractor, uriVariables); } @Override public <T> ResponseEntity<T> getForEntity(String url, Class<T> responseType, Map<String, ?> uriVariables) throws RestClientException { RequestCallback requestCallback = acceptHeaderRequestCallback(responseType); ResponseExtractor<ResponseEntity<T>> responseExtractor = responseEntityExtractor(responseType); return execute(url, HttpMethod.GET, requestCallback, responseExtractor, uriVariables); } @Override public <T> ResponseEntity<T> getForEntity(URI url, Class<T> responseType) throws RestClientException { RequestCallback requestCallback = acceptHeaderRequestCallback(responseType); ResponseExtractor<ResponseEntity<T>> responseExtractor = responseEntityExtractor(responseType); return execute(url, HttpMethod.GET, requestCallback, responseExtractor); }
举例:
ResponseEntity<Book> responseEntity = restTemplate.getForEntity("http://127.0.0.1:8080/getbook?bookname={1}", Book.class, "java"); Book book = responseEntity.getBody(); //响应体转换为Book类型 int statusCodeValue = responseEntity.getStatusCodeValue(); //响应状态码 HttpHeaders headers = responseEntity.getHeaders(); //响应头信息
发送GET请求,返回指定的Object类型
/** * 参数1: String类型 或 URI类型的请求地址 * 参数2: 指定返回的实体类型,class对象 * 参数3: uri参数,能够是变长数组或map * 返回值:responseType指定的Object类型 */ @Override public <T> T getForObject(String url, Class<T> responseType, Object... uriVariables) throws RestClientException { RequestCallback requestCallback = acceptHeaderRequestCallback(responseType); HttpMessageConverterExtractor<T> responseExtractor = new HttpMessageConverterExtractor<T>(responseType, getMessageConverters(), logger); return execute(url, HttpMethod.GET, requestCallback, responseExtractor, uriVariables); } @Override public <T> T getForObject(String url, Class<T> responseType, Map<String, ?> uriVariables) throws RestClientException { RequestCallback requestCallback = acceptHeaderRequestCallback(responseType); HttpMessageConverterExtractor<T> responseExtractor = new HttpMessageConverterExtractor<T>(responseType, getMessageConverters(), logger); return execute(url, HttpMethod.GET, requestCallback, responseExtractor, uriVariables); } @Override public <T> T getForObject(URI url, Class<T> responseType) throws RestClientException { RequestCallback requestCallback = acceptHeaderRequestCallback(responseType); HttpMessageConverterExtractor<T> responseExtractor = new HttpMessageConverterExtractor<T>(responseType, getMessageConverters(), logger); return execute(url, HttpMethod.GET, requestCallback, responseExtractor); }
举例:
Book book = restTemplate.getForObject("http://127.0.0.1:8080/getbook?bookname={1}", Book.class, "java");
发送POST请求,返回ResponseEntity
/** * 参数1: String类型 或 URI类型的请求地址 * 参数2: 请求body,能够是HttpEntity类型(可设置request header),或其它Object类型 * 参数3: 指定返回的实体类型,class对象 * 参数4: uri参数,能够是变长数组或map * 返回值:ResponseEntity<T>是Spring对HTTP响应的封装,包括了几个重要的元素,如响应码、contentType、contentLength、response header信息,response body信息等 */ @Override public <T> ResponseEntity<T> postForEntity(String url, Object request, Class<T> responseType, Object... uriVariables) throws RestClientException { RequestCallback requestCallback = httpEntityCallback(request, responseType); ResponseExtractor<ResponseEntity<T>> responseExtractor = responseEntityExtractor(responseType); return execute(url, HttpMethod.POST, requestCallback, responseExtractor, uriVariables); } @Override public <T> ResponseEntity<T> postForEntity(String url, Object request, Class<T> responseType, Map<String, ?> uriVariables) throws RestClientException { RequestCallback requestCallback = httpEntityCallback(request, responseType); ResponseExtractor<ResponseEntity<T>> responseExtractor = responseEntityExtractor(responseType); return execute(url, HttpMethod.POST, requestCallback, responseExtractor, uriVariables); } @Override public <T> ResponseEntity<T> postForEntity(URI url, Object request, Class<T> responseType) throws RestClientException { RequestCallback requestCallback = httpEntityCallback(request, responseType); ResponseExtractor<ResponseEntity<T>> responseExtractor = responseEntityExtractor(responseType); return execute(url, HttpMethod.POST, requestCallback, responseExtractor); }
举例:
//参数是Book类型,返回值是ResponseEntity<Book>类型 ResponseEntity<Book> responseEntity = restTemplate.postForEntity("http://127.0.0.1:8080/updateBook", book, Book.class); Book book = responseEntity.getBody(); //响应体转换为Book类型 int statusCodeValue = responseEntity.getStatusCodeValue(); //响应状态码 HttpHeaders headers = responseEntity.getHeaders(); //响应头信息
发送POST请求,返回指定的Object类型
/** * 参数1: String类型 或 URI类型的请求地址 * 参数2: 请求body,能够是HttpEntity类型(可设置request header),或其它Object类型 * 参数3: 指定返回的实体类型,class对象 * 参数4: uri参数,能够是变长数组或map * 返回值:responseType指定的Object类型 */ @Override public <T> T postForObject(String url, Object request, Class<T> responseType, Object... uriVariables) throws RestClientException { RequestCallback requestCallback = httpEntityCallback(request, responseType); HttpMessageConverterExtractor<T> responseExtractor = new HttpMessageConverterExtractor<T>(responseType, getMessageConverters(), logger); return execute(url, HttpMethod.POST, requestCallback, responseExtractor, uriVariables); } @Override public <T> T postForObject(String url, Object request, Class<T> responseType, Map<String, ?> uriVariables) throws RestClientException { RequestCallback requestCallback = httpEntityCallback(request, responseType); HttpMessageConverterExtractor<T> responseExtractor = new HttpMessageConverterExtractor<T>(responseType, getMessageConverters(), logger); return execute(url, HttpMethod.POST, requestCallback, responseExtractor, uriVariables); } @Override public <T> T postForObject(URI url, Object request, Class<T> responseType) throws RestClientException { RequestCallback requestCallback = httpEntityCallback(request, responseType); HttpMessageConverterExtractor<T> responseExtractor = new HttpMessageConverterExtractor<T>(responseType, getMessageConverters()); return execute(url, HttpMethod.POST, requestCallback, responseExtractor); }
举例:
//参数是Book类型,返回值也是Book类型 Book book = restTemplate.postForObject("http://127.0.0.1:8080/updatebook", book, Book.class);
HttpHeaders requestHeaders = new HttpHeaders(); requestHeaders.set("MyRequestHeader", "MyValue"); HttpEntity requestEntity = new HttpEntity(requestHeaders); HttpEntity<String> response = template.exchange( "http://example.com/hotels/{hotel}", HttpMethod.GET, //GET请求 requestEntity, //requestEntity,能够设置请求header、body String.class, "42"); String responseHeader = response.getHeaders().getFirst("MyResponseHeader"); //响应头信息 String body = response.getBody();
(1)若是是发送post、put请求,要设置请求头,能够在调用方法时的第二个参数传入HttpEntity对象,HttpEntity能够用于设置请求头信息,如
HttpHeaders requestHeaders = new HttpHeaders(); requestHeaders.set("MyRequestHeader", "MyValue"); HttpEntity requestEntity = new HttpEntity(requestHeaders); Book book = restTemplate.postForObject("http://127.0.0.1:8080/getbook", requestEntity, Book.class);
以postForObject()
方法举例,其第二个参数接收Object类型的数据,如传入的是HttpEntity,则使用它做为整个请求实体,若是传入的是其它Object类型,则将Object参数做为request body,新建一个HttpEntity做为请求实体
private HttpEntityRequestCallback(Object requestBody, Type responseType) { super(responseType); //若是是HttpEntity类型的,直接做为请求实体赋值给this.requestEntity if (requestBody instanceof HttpEntity) { this.requestEntity = (HttpEntity<?>) requestBody; } //若是requestBody不是HttpEntity类型,且不为空,以Object参数做为request body,并新建HttpEntity else if (requestBody != null) { this.requestEntity = new HttpEntity<Object>(requestBody); } else { this.requestEntity = HttpEntity.EMPTY; } }
(2)若是是其它HTTP方法调用要设置请求头,可使用exchange()方法,能够参考 官方示例
HttpHeaders requestHeaders = new HttpHeaders(); requestHeaders.set("MyRequestHeader", "MyValue"); HttpEntity requestEntity = new HttpEntity(requestHeaders); HttpEntity<String> response = template.exchange( "http://example.com/hotels/{hotel}", HttpMethod.GET, requestEntity, String.class, "42"); String responseHeader = response.getHeaders().getFirst("MyResponseHeader"); String body = response.getBody();
总之,设置request header信息,须要找到对应的restTemplate方法中可使用HttpEntity做为参数的,提早设置好请求头信息
注意:HttpEntity有4个构造方法,无参构造,只设置请求body,只设置headers,既设置headers又设置body
/** * Create a new, empty {@code HttpEntity}. */ protected HttpEntity() { this(null, null); } /** * Create a new {@code HttpEntity} with the given body and no headers. * @param body the entity body */ public HttpEntity(T body) { this(body, null); } /** * Create a new {@code HttpEntity} with the given headers and no body. * @param headers the entity headers */ public HttpEntity(MultiValueMap<String, String> headers) { this(null, headers); } /** * Create a new {@code HttpEntity} with the given body and headers. * @param body the entity body * @param headers the entity headers */ public HttpEntity(T body, MultiValueMap<String, String> headers) { this.body = body; HttpHeaders tempHeaders = new HttpHeaders(); if (headers != null) { tempHeaders.putAll(headers); } this.headers = HttpHeaders.readOnlyHttpHeaders(tempHeaders); }
使用RestTemplate中xxxForEntity()
的方法,会返回ResponseEntity,能够从中获取到响应状态码,响应头和body等信息
HttpHeaders requestHeaders = new HttpHeaders(); requestHeaders.set("MyRequestHeader", "MyValue"); HttpEntity requestEntity = new HttpEntity(requestHeaders); HttpEntity<String> response = template.exchange( "http://example.com/hotels/{hotel}", HttpMethod.GET, requestEntity, String.class, "42"); //response相关信息 String responseHeader = response.getHeaders().getFirst("MyResponseHeader"); String body = response.getBody();
ClientHttpRequestFactory是Spring定义的一个接口,其用于生产org.springframework.http.client.ClientHttpRequest
对象,RestTemplate只是模板类,抽象了不少调用方法,而底层真正使用何种框架发送HTTP请求是经过ClientHttpRequestFactory指定的
接口定义
/** * Factory for {@link ClientHttpRequest} objects. * Requests are created by the {@link #createRequest(URI, HttpMethod)} method. * ClientHttpRequest对象的工厂 * * @author Arjen Poutsma * @since 3.0 */ public interface ClientHttpRequestFactory { /** * Create a new {@link ClientHttpRequest} for the specified URI and HTTP method. * <p>The returned request can be written to, and then executed by calling * {@link ClientHttpRequest#execute()}. * 使用指定的URI和HTTP方法新建一个ClientHttpRequest对象 * 能够修改返回的request,并经过ClientHttpRequest的execute()方法执行调用 * 即调用的逻辑也被Spring封装到ClientHttpRequest中 * * @param uri the URI to create a request for * @param httpMethod the HTTP method to execute * @return the created request * @throws IOException in case of I/O errors */ ClientHttpRequest createRequest(URI uri, HttpMethod httpMethod) throws IOException; }
RestTemplate能够在构造时设置ClientHttpRequestFactory,也能够经过setRequestFactory()方法设置
构造方法设置: /** * Create a new instance of the {@link RestTemplate} based on the given {@link ClientHttpRequestFactory}. * @param requestFactory HTTP request factory to use * @see org.springframework.http.client.SimpleClientHttpRequestFactory * @see org.springframework.http.client.HttpComponentsClientHttpRequestFactory */ public RestTemplate(ClientHttpRequestFactory requestFactory) { this(); setRequestFactory(requestFactory); }
能够看到上面注释中已经给出了Spring的两种ClientHttpRequestFactory的实现类SimpleClientHttpRequestFactory
和HttpComponentsClientHttpRequestFactory
若是什么都不设置,RestTemplate默认使用的是SimpleClientHttpRequestFactory,其内部使用的是jdk的java.net.HttpURLConnection
建立底层链接,默认是没有链接池的,connectTimeout和readTimeout都是 -1,即没有超时时间
public class SimpleClientHttpRequestFactory implements ClientHttpRequestFactory, AsyncClientHttpRequestFactory { 。。。。。。 private int connectTimeout = -1; private int readTimeout = -1; //建立Request @Override public ClientHttpRequest createRequest(URI uri, HttpMethod httpMethod) throws IOException { HttpURLConnection connection = openConnection(uri.toURL(), this.proxy); prepareConnection(connection, httpMethod.name()); //bufferRequestBody默认为true if (this.bufferRequestBody) { return new SimpleBufferingClientHttpRequest(connection, this.outputStreaming); } else { return new SimpleStreamingClientHttpRequest(connection, this.chunkSize, this.outputStreaming); } } /** * Opens and returns a connection to the given URL. * 打开并返回一个指定URL的链接 * <p>The default implementation uses the given {@linkplain #setProxy(java.net.Proxy) proxy} - * if any - to open a connection. * @param url the URL to open a connection to * @param proxy the proxy to use, may be {@code null} * @return the opened connection 返回类型为 java.net.HttpURLConnection * @throws IOException in case of I/O errors */ protected HttpURLConnection openConnection(URL url, Proxy proxy) throws IOException { URLConnection urlConnection = (proxy != null ? url.openConnection(proxy) : url.openConnection()); if (!HttpURLConnection.class.isInstance(urlConnection)) { throw new IllegalStateException("HttpURLConnection required for [" + url + "] but got: " + urlConnection); } return (HttpURLConnection) urlConnection; } /** * Template method for preparing the given {@link HttpURLConnection}. * <p>The default implementation prepares the connection for input and output, and sets the HTTP method. * @param connection the connection to prepare * @param httpMethod the HTTP request method ({@code GET}, {@code POST}, etc.) * @throws IOException in case of I/O errors */ protected void prepareConnection(HttpURLConnection connection, String httpMethod) throws IOException { //若是connectTimeout大于等于0,设置链接超时时间 if (this.connectTimeout >= 0) { connection.setConnectTimeout(this.connectTimeout); } //若是readTimeout大于等于0,设置读超时时间 if (this.readTimeout >= 0) { connection.setReadTimeout(this.readTimeout); } connection.setDoInput(true); if ("GET".equals(httpMethod)) { connection.setInstanceFollowRedirects(true); } else { connection.setInstanceFollowRedirects(false); } if ("POST".equals(httpMethod) || "PUT".equals(httpMethod) || "PATCH".equals(httpMethod) || "DELETE".equals(httpMethod)) { connection.setDoOutput(true); } else { connection.setDoOutput(false); } connection.setRequestMethod(httpMethod); } 。。。。。。 }
HttpComponentsClientHttpRequestFactory底层使用Apache HttpClient建立请求,访问远程的Http服务,可使用一个已经配置好的HttpClient实例建立HttpComponentsClientHttpRequestFactory请求工厂,HttpClient实例中能够配置链接池和证书等信息
<dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> <version>x.x.x</version> <!-- springboot项目不用指定 --> </dependency>
设置超时时间,能够直接使用Spring的底层基于HttpClient的HttpComponentsClientHttpRequestFactory,此处设置的是ClientHttpRequestFactory级别的全局超时时间
@Configuration public class RestTemplateConfig { @Bean public RestTemplate restTemplate() { return new RestTemplate(clientHttpRequestFactory()); } @Bean private ClientHttpRequestFactory clientHttpRequestFactory() { HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(); factory.setConnectTimeout(30 * 1000); //链接超时时间 factory.setReadTimeout(60 * 1000); //读超时时间 return factory; } }
注意:若是经过一个HttpClient实例建立HttpComponentsClientHttpRequestFactory,并经过HttpClient指定了DefaultRequestConfig,设置了connectTimeout、readTimeout等,在实际执行请求建立request时会与HttpComponentsClientHttpRequestFactory的配置合并,connectTimeout、socketTimeout、connectionRequestTimeout 以HttpComponentsClientHttpRequestFactory的配置为准
HttpComponentsClientHttpRequestFactory: /** * Merge the given {@link HttpClient}-level {@link RequestConfig} with * the factory-level {@link RequestConfig}, if necessary. * @param clientConfig the config held by the current httpClient级别的requestConfig配置 * @return the merged request config * (may be {@code null} if the given client config is {@code null}) * @since 4.2 */ protected RequestConfig mergeRequestConfig(RequestConfig clientConfig) { if (this.requestConfig == null) { // nothing to merge return clientConfig; } RequestConfig.Builder builder = RequestConfig.copy(clientConfig); int connectTimeout = this.requestConfig.getConnectTimeout(); //HttpComponentsClientHttpRequestFactory级别的配置 if (connectTimeout >= 0) { builder.setConnectTimeout(connectTimeout); } int connectionRequestTimeout = this.requestConfig.getConnectionRequestTimeout(); if (connectionRequestTimeout >= 0) { builder.setConnectionRequestTimeout(connectionRequestTimeout); } int socketTimeout = this.requestConfig.getSocketTimeout(); if (socketTimeout >= 0) { builder.setSocketTimeout(socketTimeout); } return builder.build(); }
上例中虽然没有指定http链接池,但** HttpComponentsClientHttpRequestFactory无参构造会建立一个HttpClient,并默认使用了链接池配置,MaxTotal=10,DefaultMaxPerRoute=5 **,具体以下:
HttpComponentsClientHttpRequestFactory: /** * Create a new instance of the {@code HttpComponentsClientHttpRequestFactory} * with a default {@link HttpClient}. */ public HttpComponentsClientHttpRequestFactory() { this(HttpClients.createSystem()); } HttpClients: /** * Creates {@link CloseableHttpClient} instance with default * configuration based on system properties. * 建立CloseableHttpClient实例使用基于system properties的默认配置 */ public static CloseableHttpClient createSystem() { return HttpClientBuilder.create().useSystemProperties().build(); } HttpClientBuilder: /** * Use system properties when creating and configuring default * implementations. */ public final HttpClientBuilder useSystemProperties() { this.systemProperties = true; //设置systemProperties为true return this; } public CloseableHttpClient build() { HttpClientConnectionManager connManagerCopy = this.connManager; //没有设置,为null if (connManagerCopy == null) { 。。。。。。 //建立链接池管理器PoolingHttpClientConnectionManager @SuppressWarnings("resource") final PoolingHttpClientConnectionManager poolingmgr = new PoolingHttpClientConnectionManager( RegistryBuilder.<ConnectionSocketFactory>create() .register("http", PlainConnectionSocketFactory.getSocketFactory()) .register("https", sslSocketFactoryCopy) .build(), null, null, dnsResolver, connTimeToLive, connTimeToLiveTimeUnit != null ? connTimeToLiveTimeUnit : TimeUnit.MILLISECONDS); if (defaultSocketConfig != null) { poolingmgr.setDefaultSocketConfig(defaultSocketConfig); } if (defaultConnectionConfig != null) { poolingmgr.setDefaultConnectionConfig(defaultConnectionConfig); } //因为是HttpClientBuilder.create().useSystemProperties().build(),systemProperties为true if (systemProperties) { String s = System.getProperty("http.keepAlive", "true"); //http.keepAlive默认值为true if ("true".equalsIgnoreCase(s)) { s = System.getProperty("http.maxConnections", "5"); //默认值为5 final int max = Integer.parseInt(s); poolingmgr.setDefaultMaxPerRoute(max); //DefaultMaxPerRoute=5 poolingmgr.setMaxTotal(2 * max); //MaxTotal=10 } } if (maxConnTotal > 0) { poolingmgr.setMaxTotal(maxConnTotal); } if (maxConnPerRoute > 0) { poolingmgr.setDefaultMaxPerRoute(maxConnPerRoute); } connManagerCopy = poolingmgr; } }
@Configuration public class RestTemplateConfig { @Bean public RestTemplate restTemplate() { return new RestTemplate(clientHttpRequestFactory()); } @Bean public HttpComponentsClientHttpRequestFactory clientHttpRequestFactory() { try { HttpClientBuilder httpClientBuilder = HttpClientBuilder.create(); //开始设置链接池 PoolingHttpClientConnectionManager poolingHttpClientConnectionManager = new PoolingHttpClientConnectionManager(); poolingHttpClientConnectionManager.setMaxTotal(100); //最大链接数 poolingHttpClientConnectionManager.setDefaultMaxPerRoute(20); //同路由并发数 httpClientBuilder.setConnectionManager(poolingHttpClientConnectionManager); HttpClient httpClient = httpClientBuilder.build(); // httpClient链接配置 HttpComponentsClientHttpRequestFactory clientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory(httpClient); clientHttpRequestFactory.setConnectTimeout(30 * 1000); //链接超时 clientHttpRequestFactory.setReadTimeout(60 * 1000); //数据读取超时时间 clientHttpRequestFactory.setConnectionRequestTimeout(30 * 1000); //链接不够用的等待时间 return clientHttpRequestFactory; } catch (Exception e) { logger.error("初始化clientHttpRequestFactory出错", e); } return null; } }
RestTemplate的无参构造中默认会初始化不少messageConverters,用于请求/响应中的消息转换
/** * Create a new instance of the {@link RestTemplate} using default settings. * Default {@link HttpMessageConverter}s are initialized. * 使用默认配置建立一个RestTemplate实例 * 默认的HttpMessageConverter集合被初始化 */ public RestTemplate() { this.messageConverters.add(new ByteArrayHttpMessageConverter()); this.messageConverters.add(new StringHttpMessageConverter()); this.messageConverters.add(new ResourceHttpMessageConverter()); this.messageConverters.add(new SourceHttpMessageConverter<Source>()); this.messageConverters.add(new AllEncompassingFormHttpMessageConverter()); if (romePresent) { this.messageConverters.add(new AtomFeedHttpMessageConverter()); this.messageConverters.add(new RssChannelHttpMessageConverter()); } if (jackson2XmlPresent) { this.messageConverters.add(new MappingJackson2XmlHttpMessageConverter()); } else if (jaxb2Present) { this.messageConverters.add(new Jaxb2RootElementHttpMessageConverter()); } /** * 若是类路径下包含com.fasterxml.jackson.databind.ObjectMapper 和 com.fasterxml.jackson.core.JsonGenerator * 使用jackson作http请求、响应的json转换 */ if (jackson2Present) { this.messageConverters.add(new MappingJackson2HttpMessageConverter()); } else if (gsonPresent) { //类路径下包含 com.google.gson.Gson this.messageConverters.add(new GsonHttpMessageConverter()); } }
springboot项目默认使用jackson作json转换
排除jackson的HttpMessageConverter转换器有两种方式:
(1)类路径下去掉jackson的支持
从RestTemplate的无参构造能够看出,须要判断类路径下是否有jackson的相关类,有才会添加MappingJackson2HttpMessageConverter,故能够在pom.xml中排除jackson的支持,以springboot项目举例
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <exclusions> <exclusion> <artifactId>jackson-databind</artifactId> <groupId>com.fasterxml.jackson.core</groupId> </exclusion> </exclusions> </dependency>
(2)在初始化配置RestTemplate时,去掉其默认的MappingJackson2HttpMessageConverter
@Bean public RestTemplate restTemplate() { RestTemplate restTemplate = new RestTemplate(); restTemplate.setRequestFactory(clientHttpRequestFactory()); //restTemplate默认的HttpMessageConverter List<HttpMessageConverter<?>> messageConverters = restTemplate.getMessageConverters(); List<HttpMessageConverter<?>> messageConvertersNew = new ArrayList<HttpMessageConverter<?>>(); for(HttpMessageConverter httpMessageConverter : messageConverters){ //跳过MappingJackson2HttpMessageConverter if (httpMessageConverter instanceof MappingJackson2HttpMessageConverter) continue; messageConvertersNew.add(httpMessageConverter); } //添加fastjson转换器 messageConvertersNew.add(fastJsonHttpMessageConverter()); return restTemplate; } @Bean public HttpMessageConverter fastJsonHttpMessageConverter() { //MediaType List<MediaType> mediaTypes = new ArrayList<>(); mediaTypes.add(MediaType.APPLICATION_JSON_UTF8); //FastJsonConfig FastJsonConfig fastJsonConfig = new FastJsonConfig(); fastJsonConfig.setSerializerFeatures(SerializerFeature.WriteMapNullValue, SerializerFeature.QuoteFieldNames); //建立FastJsonHttpMessageConverter4 Spring 4.2后使用 FastJsonHttpMessageConverter4 fastJsonHttpMessageConverter = new FastJsonHttpMessageConverter4(); fastJsonHttpMessageConverter.setSupportedMediaTypes(mediaTypes); fastJsonHttpMessageConverter.setFastJsonConfig(fastJsonConfig); return fastJsonHttpMessageConverter; }
SpringBoot项目能够经过上面的方式,@Bean往Spring容器中注册一个配置好的RestTemplate实例,也能够参考 SpringBoot官方 的方式自定义RestTemplate
因为RestTemplate实例在使用前常常须要自定义,SpringBoot没有提供自动配置好的RestTemplate,可是自动配置好了能够用于建立RestTemplate的RestTemplateBuilder
实例,能够按以下使用
@Service public class MyBean { private final RestTemplate restTemplate; public MyBean(RestTemplateBuilder restTemplateBuilder) { this.restTemplate = restTemplateBuilder.build(); } public Details someRestCall(String name) { return this.restTemplate.getForObject("/{name}/details", Details.class, name); } }
RestTemplate自定义主要有三种方法,具体取决于但愿自定义应用的范围
类范围。为了尽可能缩小自定义的范围,在类中注入自动配置的RestTemplateBuilder
,而后根据需求调用它的配置方法,每次调用配置方法都会 new RestTemplateBuilder()并返回,因此对RestTemplateBuilder的配置只会影响由它建立的RestTemplate
应用范围。可使用RestTemplateCustomizer
来自定义应用范围的的RestTemplate,全部注册到Spring容器的RestTemplateCustomizer
都会自动生效。以下,经过RestTemplateCustomizer设置链接池
@Bean public RestTemplateCustomizer restTemplateCustomizer(){ return new RestTemplateCustomizer(){ @Override public void customize(RestTemplate restTemplate) { HttpClientBuilder httpClientBuilder = HttpClientBuilder.create(); //建立链接管理器 PoolingHttpClientConnectionManager poolingHttpClientConnectionManager = new PoolingHttpClientConnectionManager(); poolingHttpClientConnectionManager.setMaxTotal(100); poolingHttpClientConnectionManager.setDefaultMaxPerRoute(20); httpClientBuilder.setConnectionManager(poolingHttpClientConnectionManager); //建立httpClient HttpClient httpClient = httpClientBuilder.build(); //建立HttpComponentsClientHttpRequestFactory HttpComponentsClientHttpRequestFactory httpComponentsClientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory(httpClient); httpComponentsClientHttpRequestFactory.setConnectTimeout(10 * 1000); httpComponentsClientHttpRequestFactory.setReadTimeout(60 * 1000); httpComponentsClientHttpRequestFactory.setConnectionRequestTimeout(20 * 1000); restTemplate.setRequestFactory(httpComponentsClientHttpRequestFactory); } }; }
最后,最极端的(也是不多使用的)选项是建立你本身的RestTemplateBuilder
bean。这将关闭RestTemplateBuilder
的自动配置,并阻止使用任何RestTemplateCustomizer
bean