spring-RestTemplate:設計模式

做用

用於http請求,且封裝了不一樣http框架,
1.jdk api //默認
2.httpclient //1.鏈接池2.超時
3.okhttp //異步 java

RestTemplate,自己不實現http請求,http請求的底層實現是其餘框架,RestTemplate的核心有兩個
1.更方便http請求
2.且能夠切換不一樣http框架
不一樣http框架,提供的功能不徹底同樣web

應用層-使用

步驟
1.獲取模板
2.調用模板的方法spring

List<AuditResult> auditResultList = null; //響應數據
try {
   auditResultList = HttpClientUtil.getTemplate().postForObject(url,
         audits //入參數據的類型通常是map/list, List.class //響應數據的數據類型);
} catch (Throwable e) {
   log.error(msg + " 調用風控系統超時!" + e.getMessage());
   return;
}

切換默認jdk api爲httpclient

默認是jdk api,爲何要切換?
由於有更多的配置項,好比
1.鏈接池
2.超時apache


如何切換?
須要簡單封裝一下,
1.用httpclient的客戶端請求類CloseableHttpClient覆蓋默認的
2.配置鏈接池
3.配置超時json

package xxx.util;

import java.util.ArrayList;
import java.util.List;

import org.apache.http.client.config.RequestConfig;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.web.client.RestTemplate;

import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;

public class HttpClientUtil {
//鏈接池配置項
   private static int POOLSIZE = 150;// 鏈接池
   private static PoolingHttpClientConnectionManager connMgr = null;
//超時配置項
   private final static int SOCKETTIMEOUT = 1000;// 讀取響應超時時間
   private final static int CONNECTIONREQUESTTIMEOUT = 3000; // 從鏈接池獲取鏈接超時時間
   private final static int CONNECTTIMEOUT = 2000;// 鏈接超時時間

   public static RestTemplate getTemplate() {
      CloseableHttpClient httpClient = getConnection();
      RestTemplate template = new RestTemplate(
            new HttpComponentsClientHttpRequestFactory(httpClient)); //用httpclient的客戶端請求類CloseableHttpClient覆蓋默認的

      List<HttpMessageConverter<?>> converters = new ArrayList<HttpMessageConverter<?>>();
      // 採用fastjson進行數據轉換
      FastJsonHttpMessageConverter fastjson = new FastJsonHttpMessageConverter();
      fastjson.setFeatures(SerializerFeature.WriteClassName,
            SerializerFeature.BrowserCompatible,
            SerializerFeature.DisableCircularReferenceDetect);
      converters.add(fastjson);
      template.setMessageConverters(converters);
      return template;
   }

   private static CloseableHttpClient getConnection() {
      if (connMgr == null) {
         // 建立連接池。鏈接池能夠併發請求100個鏈接
         connMgr = new PoolingHttpClientConnectionManager();
         connMgr.setMaxTotal(POOLSIZE + 1);
         connMgr.setDefaultMaxPerRoute(POOLSIZE);
      }
      RequestConfig requestConfig = RequestConfig.custom()
            .setConnectionRequestTimeout(CONNECTIONREQUESTTIMEOUT)
            .setConnectTimeout(CONNECTTIMEOUT)
            .setSocketTimeout(SOCKETTIMEOUT).build(); //配置超時
      CloseableHttpClient httpClient = HttpClients.custom()
            .setConnectionManager(connMgr) //配置鏈接池
            .setDefaultRequestConfig(requestConfig).build();
      return httpClient;
   }

}

源碼

流程是
1.獲取客戶端
2.請求服務器設計模式

無論是哪種http框架,流程都是同樣。核心步驟就是這兩個。api

public class RestTemplate extends InterceptingHttpAccessor implements RestOperations {

protected <T> T doExecute(URI url, HttpMethod method, RequestCallback requestCallback, ResponseExtractor<T> responseExtractor) throws RestClientException {
    Assert.notNull(url, "'url' must not be null");
    Assert.notNull(method, "'method' must not be null");
    ClientHttpResponse response = null;

    Object var7;
    try {
        ClientHttpRequest request = this.createRequest(url, method); //獲取http請求客戶端
        if (requestCallback != null) {
            requestCallback.doWithRequest(request);
        }

        response = request.execute(); //請求服務器
        if (!this.getErrorHandler().hasError(response)) {
            this.logResponseStatus(method, url, response);
        } else {
            this.handleResponseError(method, url, response);
        }

        if (responseExtractor == null) {
            var7 = null;
            return var7;
        }

        var7 = responseExtractor.extractData(response);
    } catch (IOException var11) {
        throw new ResourceAccessException("I/O error on " + method.name() + " request for \"" + url + "\":" + var11.getMessage(), var11);
    } finally {
        if (response != null) {
            response.close();
        }

    }

    return var7;
}

因爲切換了http框架,客戶端類如今是CloseableHttpClient(httpclient框架的客戶端類)。其實就是兩個步驟,
1.封裝的時候,用httpclient的客戶端請求類CloseableHttpClient覆蓋默認的
2.底層請求服務器的時候,就使用切換以後的客戶端服務器

設計模式

看名字是模板模式,spring裏還有其餘的相似名字,JdbcTemplate(mybatis/hibernate等dao框架)、RedisTemplate。mybatis

RestTemplate也是不一樣http框架(jdk api/httpclient/okhttp)的封裝。併發

slf也是對不一樣日誌框架(log4j等)的封裝,叫門面模式。

無論模式名字叫什麼,本質是
1.本身不實現,只是封裝其餘框架
底層實現是框架
2.能夠切換不一樣框架
不一樣框架,提供的功能不徹底同樣

準確的說,模式名字應該叫切換模式,即1.封裝了不一樣框架2.而後,實現了對不一樣框架的切換

相關文章
相關標籤/搜索