javascript
Spring RestTemplate 实践
什么是RestTemplate?
RestTemplate是Spring提供的用于訪問Rest服務的客戶端,RestTemplate提供了多種便捷訪問遠程Http服務的方法,能夠大大提高客戶端的編寫效率。
調用RestTemplate的默認構造函數(shù),RestTemplate對象在底層通過使用java.net包下的實現(xiàn)創(chuàng)建HTTP 請求,可以通過使用ClientHttpRequestFactory指定不同的HTTP請求方式。
ClientHttpRequestFactory接口主要提供了兩種實現(xiàn)方式
一種是SimpleClientHttpRequestFactory,使用J2SE提供的方式(既java.net包提供的方式)創(chuàng)建底層的Http請求連接。
一種方式是使用HttpComponentsClientHttpRequestFactory方式,底層使用HttpClient訪問遠程的Http服務,使用HttpClient可以配置連接池和證書等信息。
使用RestTemplate
Xml配置的方式
請查看RestTemplate源碼了解細節(jié),知其然知其所以然!
RestTemplate默認是使用SimpleClientHttpRequestFactory,內部是調用jdk的HttpConnection,默認超時為-1
@Autowired
RestTemplate simpleRestTemplate
@Autowired
RestTemplate restTemplate
基于jdk的spring的RestTemplate
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"default-autowire="byName" default-lazy-init="true"><!--方式一、使用jdk的實現(xiàn)--><bean id="ky.requestFactory" class="org.springframework.http.client.SimpleClientHttpRequestFactory"><property name="readTimeout" value="10000"/><property name="connectTimeout" value="5000"/></bean><bean id="simpleRestTemplate" class="org.springframework.web.client.RestTemplate"><constructor-arg ref="ky.requestFactory"/><property name="messageConverters"><list><bean class="org.springframework.http.converter.FormHttpMessageConverter"/><bean class="org.springframework.http.converter.xml.MappingJackson2XmlHttpMessageConverter"/><bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"/><bean class="org.springframework.http.converter.StringHttpMessageConverter"><property name="supportedMediaTypes"><list><value>text/plain;charset=UTF-8</value></list></property></bean></list></property></bean></beans>使用Httpclient連接池的方式
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"default-autowire="byName" default-lazy-init="true"><!--方式二、使用httpclient的實現(xiàn),帶連接池--><bean id="ky.pollingConnectionManager" class="org.apache.http.impl.conn.PoolingHttpClientConnectionManager"><!--整個連接池的并發(fā)--><property name="maxTotal" value="1000" /><!--每個主機的并發(fā)--><property name="defaultMaxPerRoute" value="1000" /></bean><bean id="ky.httpClientBuilder" class="org.apache.http.impl.client.HttpClientBuilder" factory-method="create"><property name="connectionManager" ref="ky.pollingConnectionManager" /><!--開啟重試--><property name="retryHandler"><bean class="org.apache.http.impl.client.DefaultHttpRequestRetryHandler"><constructor-arg value="2"/><constructor-arg value="true"/></bean></property><property name="defaultHeaders"><list><bean class="org.apache.http.message.BasicHeader"><constructor-arg value="User-Agent"/><constructor-arg value="Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.16 Safari/537.36"/></bean><bean class="org.apache.http.message.BasicHeader"><constructor-arg value="Accept-Encoding"/><constructor-arg value="gzip,deflate"/></bean><bean class="org.apache.http.message.BasicHeader"><constructor-arg value="Accept-Language"/><constructor-arg value="zh-CN"/></bean></list></property></bean><bean id="ky.httpClient" factory-bean="ky.httpClientBuilder" factory-method="build" /><bean id="ky.clientHttpRequestFactory" class="org.springframework.http.client.HttpComponentsClientHttpRequestFactory"><constructor-arg ref="ky.httpClient"/><!--連接超時時間,毫秒--><property name="connectTimeout" value="5000"/><!--讀寫超時時間,毫秒--><property name="readTimeout" value="10000"/></bean><bean id="restTemplate" class="org.springframework.web.client.RestTemplate"><constructor-arg ref="ky.clientHttpRequestFactory"/><property name="errorHandler"><bean class="org.springframework.web.client.DefaultResponseErrorHandler"/></property><property name="messageConverters"><list><bean class="org.springframework.http.converter.FormHttpMessageConverter"/><bean class="org.springframework.http.converter.xml.MappingJackson2XmlHttpMessageConverter"/><bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"/><bean class="org.springframework.http.converter.StringHttpMessageConverter"><property name="supportedMediaTypes"><list><value>text/plain;charset=UTF-8</value></list></property></bean></list></property></bean></beans>Bean初始化方式
線程安全的單例(懶漢模式)、靜態(tài)工具類
基于jdk的spring的RestTemplate
import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.context.annotation.Lazy; import org.springframework.http.client.SimpleClientHttpRequestFactory; import org.springframework.http.converter.FormHttpMessageConverter; import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.converter.StringHttpMessageConverter; import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; import org.springframework.http.converter.xml.MappingJackson2XmlHttpMessageConverter; import org.springframework.stereotype.Component; import org.springframework.web.client.DefaultResponseErrorHandler; import org.springframework.web.client.RestTemplate;import javax.annotation.PostConstruct; import java.nio.charset.Charset; import java.util.ArrayList; import java.util.List;/*** @title:基于jdk的spring的RestTemplate* @author:liuxing* @date:2015-05-18 09:35*/ @Component @Lazy(false) public class SimpleRestClient {private static final Logger LOGGER = LoggerFactory.getLogger(SimpleRestClient.class);private static RestTemplate restTemplate;static {SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();requestFactory.setReadTimeout(5000);requestFactory.setConnectTimeout(5000);// 添加轉換器List<HttpMessageConverter<?>> messageConverters = new ArrayList<>();messageConverters.add(new StringHttpMessageConverter(Charset.forName("UTF-8")));messageConverters.add(new FormHttpMessageConverter());messageConverters.add(new MappingJackson2XmlHttpMessageConverter());messageConverters.add(new MappingJackson2HttpMessageConverter());restTemplate = new RestTemplate(messageConverters);restTemplate.setRequestFactory(requestFactory);restTemplate.setErrorHandler(new DefaultResponseErrorHandler());LOGGER.info("SimpleRestClient初始化完成");}private SimpleRestClient() {}@PostConstructpublic static RestTemplate getClient() {return restTemplate;}}使用Httpclient連接池的方式
import java.nio.charset.Charset; import java.util.ArrayList; import java.util.List; import java.util.concurrent.TimeUnit;import org.apache.http.Header; import org.apache.http.client.HttpClient; import org.apache.http.impl.client.DefaultConnectionKeepAliveStrategy; import org.apache.http.impl.client.DefaultHttpRequestRetryHandler; import org.apache.http.impl.client.HttpClientBuilder; import org.apache.http.impl.client.HttpClients; import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; import org.apache.http.message.BasicHeader; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; import org.springframework.http.converter.FormHttpMessageConverter; import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.converter.StringHttpMessageConverter; import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; import org.springframework.http.converter.xml.MappingJackson2XmlHttpMessageConverter; import org.springframework.web.client.DefaultResponseErrorHandler; import org.springframework.web.client.RestTemplate;/*** 使用spring的restTemplate替代httpclient工具*/ public class RestClient {private static final Logger LOGGER = LoggerFactory.getLogger(RestClient.class);private static RestTemplate restTemplate;private final static Object syncLock = new Object();private static void initRestTemplate() {// 長連接保持30秒PoolingHttpClientConnectionManager pollingConnectionManager = new PoolingHttpClientConnectionManager(30, TimeUnit.SECONDS);// 總連接數(shù)pollingConnectionManager.setMaxTotal(1000);// 同路由的并發(fā)數(shù)pollingConnectionManager.setDefaultMaxPerRoute(1000);HttpClientBuilder httpClientBuilder = HttpClients.custom();httpClientBuilder.setConnectionManager(pollingConnectionManager);// 重試次數(shù),默認是3次,沒有開啟httpClientBuilder.setRetryHandler(new DefaultHttpRequestRetryHandler(2, true));// 保持長連接配置,需要在頭添加Keep-AlivehttpClientBuilder.setKeepAliveStrategy(new DefaultConnectionKeepAliveStrategy());// RequestConfig.Builder builder = RequestConfig.custom(); // builder.setConnectionRequestTimeout(200); // builder.setConnectTimeout(5000); // builder.setSocketTimeout(5000); // // RequestConfig requestConfig = builder.build(); // httpClientBuilder.setDefaultRequestConfig(requestConfig);List<Header> headers = new ArrayList<>();headers.add(new BasicHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.16 Safari/537.36"));headers.add(new BasicHeader("Accept-Encoding", "gzip,deflate"));headers.add(new BasicHeader("Accept-Language", "zh-CN"));headers.add(new BasicHeader("Connection", "Keep-Alive"));httpClientBuilder.setDefaultHeaders(headers);HttpClient httpClient = httpClientBuilder.build();// httpClient連接配置,底層是配置RequestConfigHttpComponentsClientHttpRequestFactory clientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory(httpClient);// 連接超時clientHttpRequestFactory.setConnectTimeout(5000);// 數(shù)據(jù)讀取超時時間,即SocketTimeoutclientHttpRequestFactory.setReadTimeout(5000);// 連接不夠用的等待時間,不宜過長,必須設置,比如連接不夠用時,時間過長將是災難性的clientHttpRequestFactory.setConnectionRequestTimeout(200);// 緩沖請求數(shù)據(jù),默認值是true。通過POST或者PUT大量發(fā)送數(shù)據(jù)時,建議將此屬性更改為false,以免耗盡內存。// clientHttpRequestFactory.setBufferRequestBody(false);// 添加內容轉換器List<HttpMessageConverter<?>> messageConverters = new ArrayList<>();messageConverters.add(new StringHttpMessageConverter(Charset.forName("UTF-8")));messageConverters.add(new FormHttpMessageConverter());messageConverters.add(new MappingJackson2XmlHttpMessageConverter());messageConverters.add(new MappingJackson2HttpMessageConverter());restTemplate = new RestTemplate(messageConverters);restTemplate.setRequestFactory(clientHttpRequestFactory);restTemplate.setErrorHandler(new DefaultResponseErrorHandler());LOGGER.info("RestClient初始化完成");}private RestClient() {}public static RestTemplate getClient() {if(restTemplate == null){synchronized (syncLock) {if(restTemplate == null){initRestTemplate();}}}return restTemplate;}}HttpClientUtils
import java.util.Map;import org.apache.commons.collections.MapUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.http.HttpEntity; import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap;/**** 類功能說明:httpclient工具類,基于httpclient 4.x*/ public class HttpClientUtils {private static final Logger LOGGER = LoggerFactory.getLogger(HttpClientUtils.class);/*** post請求* @param url* @param formParams* @return*/public static String doPost(String url, Map<String, String> formParams) {if (MapUtils.isEmpty(formParams)) {return doPost(url);}try {MultiValueMap<String, String> requestEntity = new LinkedMultiValueMap<>();formParams.keySet().stream().forEach(key -> requestEntity.add(key, MapUtils.getString(formParams, key, "")));return RestClient.getClient().postForObject(url, requestEntity, String.class);} catch (Exception e) {LOGGER.error("POST請求出錯:{}", url, e);}return null;}/*** post請求* @param url* @return*/public static String doPost(String url) {try {return RestClient.getClient().postForObject(url, HttpEntity.EMPTY, String.class);} catch (Exception e) {LOGGER.error("POST請求出錯:{}", url, e);}return null;}/*** get請求* @param url* @return*/public static String doGet(String url) {try {return RestClient.getClient().getForObject(url, String.class);} catch (Exception e) {LOGGER.error("GET請求出錯:{}", url, e);}return null;}}ErrorHolder
自定義的一個異常結果包裝類
使用樣例
api里面可以做自動的參數(shù)匹配:
如:http://you domainn name/test?empNo={empNo},則下面方法的最后一個參數(shù)為數(shù)據(jù)匹配參數(shù),會自動根據(jù)key進行查找,然后替換
API沒有聲明異常,注意進行異常處理
更多使用語法請查看API文檔
ResponseEntity<List<KyArea>> result = RestClient.getClient().exchange(DIVIDE_PLATE_API, HttpMethod.GET, HttpEntity.EMPTY, new ParameterizedTypeReference<List<KyArea>>() {}, map("empNo", empNo)); List<KyArea> list = result.getBody();ResponseEntity<KyArea> result = RestClient.getClient().exchange(DIVIDE_PLATE_API, HttpMethod.GET, HttpEntity.EMPTY, KyArea.class, map("empNo", empNo)); KyArea kyArea = result.getBody();更多
RestTemplate API說明和使用參考
http://docs.spring.io/spring/docs/4.1.x/javadoc-api/org/springframework/web/client/RestTemplate.html
http://docs.spring.io/spring/docs/4.1.x/javadoc-api/org/springframework/http/client/SimpleClientHttpRequestFactory.html
http://docs.spring.io/spring/docs/4.1.x/javadoc-api/org/springframework/http/client/HttpComponentsClientHttpRequestFactory.html
HttpClient官方示例和參數(shù)配置說明
http://hc.apache.org/httpcomponents-client-4.4.x/examples.html
http://hc.apache.org/httpcomponents-client-4.4.x/tutorial/html/index.html
依賴
spring 3.x以上
注意點
1.關于httpclient配置的defaultMaxPerRoute和maxTotal
defaultMaxPerRoute:最大路由并發(fā)數(shù),以主機為單位
maxTotal:整個連接池的并發(fā)數(shù)
例如:
defaultMaxPerRoute為10,maxTotal為100
假設只會訪問http://www.baidu.com和http://www.google.com
那么能同時并發(fā)到客源的只能是10,房源也是10,整個連接永遠不會到100
2.部分方法注意查看源碼,默認構造里面會新增常用的數(shù)據(jù)轉換器,spring對jackson比較情有獨鐘,在解析xml和json時,優(yōu)先使用jackson
/*** Create a new instance of the {@link RestTemplate} using default settings.* Default {@link HttpMessageConverter}s are initialized.*/ 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) {messageConverters.add(new MappingJackson2XmlHttpMessageConverter());}else if (jaxb2Present) {this.messageConverters.add(new Jaxb2RootElementHttpMessageConverter());}if (jackson2Present) {this.messageConverters.add(new MappingJackson2HttpMessageConverter());}else if (gsonPresent) {this.messageConverters.add(new GsonHttpMessageConverter());} }/*** 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); }再看添加轉換器的方法外部添加轉換器時,this.messageConverters.clear();會先清除已有的,需要注意
/*** 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*/ public RestTemplate(List<HttpMessageConverter<?>> messageConverters) {Assert.notEmpty(messageConverters, "'messageConverters' must not be empty");this.messageConverters.addAll(messageConverters); }/*** Set the message body converters to use.* <p>These converters are used to convert from and to HTTP requests and responses.*/ public void setMessageConverters(List<HttpMessageConverter<?>> messageConverters) {Assert.notEmpty(messageConverters, "'messageConverters' must not be empty");// Take getMessageConverters() List as-is when passed in hereif (this.messageConverters != messageConverters) {this.messageConverters.clear();this.messageConverters.addAll(messageConverters);} }本文轉自:http://liuxing.info/2015/05/21/RestTemplate%E5%AE%9E%E8%B7%B5/
總結
以上是生活随笔為你收集整理的Spring RestTemplate 实践的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: JS遮罩效果
- 下一篇: 2022美国科学院院士名单公布:图灵奖得