天天看點

java實用型-高并發下RestTemplate的正确使用前言一、RestTemplate是什麼?二、如何使用三、高并發下的RestTemplate使用總結

高并發下RestTemplate的正确使用

  • 前言
  • 一、RestTemplate是什麼?
  • 二、如何使用
    • 1.建立一個bean
    • 2.使用步驟
  • 三、高并發下的RestTemplate使用
  • 總結

前言

如果java項目裡有調用第三方的http接口,我們可以使用RestTemplate去遠端通路。也支援配置連接配接逾時和響應逾時,還可以配置各種長連接配接政策,也可以支援長連接配接預熱,在高并發下,合理的配置使用能夠有效提高第三方接口響應時間。

一、RestTemplate是什麼?

RestTemplate是Spring提供的用于通路Rest服務的用戶端,RestTemplate提供了多種便捷通路遠端Http服務的方法,能夠大大提高用戶端的編寫效率。

二、如何使用

1.建立一個bean

以下代碼配置比較簡單,隻設定了連接配接逾時時間和響應逾時時間

/**
 * restTemplate配置
 *
 * @author Songsong
 * @date 2020-08-17 15:09
 */
@Configuration
public class RestTemplateConfiguration {
    @Bean(name = "restTemplate")
    public RestTemplate restTemplate() {
        SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
        //設定連接配接逾時時間1s
        factory.setConnectTimeout(1000);
        //設定讀取時間1s
        factory.setReadTimeout(1000);
        return new RestTemplate(factory);
    }

}
           

2.使用步驟

在需要使用的地方使用@Resource或者@Autowired注入進來

@Resource
private RestTemplate restTemplate;
           

然後我們平常調用第三方的接口是get方式和post方式,restTemplate提供getForEntity和postForEntity方法支援這兩種方式,直接調用即可,源碼分别如下:

getForEntity方法:

public <T> ResponseEntity<T> getForEntity(String url, Class<T> responseType, Object... uriVariables) throws RestClientException {
        RequestCallback requestCallback = this.acceptHeaderRequestCallback(responseType);
        ResponseExtractor<ResponseEntity<T>> responseExtractor = this.responseEntityExtractor(responseType);
        return (ResponseEntity)nonNull(this.execute(url, HttpMethod.GET, requestCallback, responseExtractor, uriVariables));
    }
           

postForEntity方法:

public <T> ResponseEntity<T> postForEntity(String url, @Nullable Object request, Class<T> responseType, Object... uriVariables) throws RestClientException {
        RequestCallback requestCallback = this.httpEntityCallback(request, responseType);
        ResponseExtractor<ResponseEntity<T>> responseExtractor = this.responseEntityExtractor(responseType);
        return (ResponseEntity)nonNull(this.execute(url, HttpMethod.POST, requestCallback, responseExtractor, uriVariables));
    }
           

源碼中還有很多以上兩種其他的重載方法,以上是作者平常項目中用的最多的一種,參數有url(第三方http連結)、request是請求所需的參數,responseType是傳回類型裡的泛型。

隻需要解析傳回的參數即可。

三、高并發下的RestTemplate使用

在平常的開發中,以上簡單的配置可能就夠用了,但是在高并發下,對接口響應時間要求很高,是以我們需要盡量的提高第三方接口響應時間。在RestTemplate中可以使用httpClient長連接配接,關于httpClient長連接配接的介紹我們可以參考:HTTPclient保持長連接配接

以下代碼我們設定了長連接配接預熱的功能,以及路由并發數:

@Slf4j
@Configuration
public class RestTemplateConfiguration {

    @Bean(name = "restTemplate")
    public RestTemplate restTemplate() {
       return getRestTemplate(3, "https://www.baidu.com/......");
    }

    private RestTemplate getRestTemplate(int maxTotal, String preHeatUrl) {
        HttpComponentsClientHttpRequestFactory httpRequestFactory = httpComponentsClientHttpRequestFactory(maxTotal);
        RestTemplate restTemplate = new RestTemplate(httpRequestFactory);
        //解決首次預熱耗時長
        if (StringUtils.isNotEmpty(preHeatUrl)) {
            try {
                restTemplate.postForEntity(preHeatUrl, "", String.class);
            } catch (Exception e) {
                log.error("preHeat url error:{}", e.getMessage());
            }
        }
        return restTemplate;
    }

    /**
     * ClientHttpRequestFactory接口的另一種實作方式(推薦使用),即:
     * HttpComponentsClientHttpRequestFactory:底層使用Httpclient連接配接池的方式建立Http連接配接請求
     *
     * @return
     */
    private HttpComponentsClientHttpRequestFactory httpComponentsClientHttpRequestFactory(int maxTotal) {
        //Httpclient連接配接池,長連接配接保持時間
        PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(1, TimeUnit.HOURS);
        //設定總連接配接數
        connectionManager.setMaxTotal(maxTotal);
        //設定同路由的并發數
        connectionManager.setDefaultMaxPerRoute(maxTotal);
        //設定header
        List<Header> headers = new ArrayList<Header>();
        headers.add(new BasicHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.3; rv:36.0) Gecko/20100101 Firefox/36.04"));
        headers.add(new BasicHeader("Accept-Encoding", "gzip, deflate"));
        headers.add(new BasicHeader("Accept-Language", "zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3"));
        headers.add(new BasicHeader("Connection", "keep-alive"));
        //建立HttpClient
        HttpClient httpClient = HttpClientBuilder.create()
                .setConnectionManager(connectionManager)
                .setDefaultHeaders(headers)
                .setRetryHandler(new DefaultHttpRequestRetryHandler(3, true)) //設定重試次數
                .setKeepAliveStrategy(new DefaultConnectionKeepAliveStrategy()) //設定保持長連接配接
                .build();
        //建立HttpComponentsClientHttpRequestFactory執行個體
        HttpComponentsClientHttpRequestFactory requestFactory =
                new HttpComponentsClientHttpRequestFactory(httpClient);
        //設定用戶端和服務端建立連接配接的逾時時間
        requestFactory.setConnectTimeout(10000);
        //設定用戶端從服務端讀取資料的逾時時間
        requestFactory.setReadTimeout(5000);
        //設定從連接配接池擷取連接配接的逾時時間,不宜過長
        requestFactory.setConnectionRequestTimeout(2000);
        //緩沖請求資料,預設為true。通過POST或者PUT大量發送資料時,建議将此更改為false,以免耗盡記憶體
        requestFactory.setBufferRequestBody(false);
        return requestFactory;
    }
           

(1)設定預熱功能

我們可以看到,在getRestTemplate方法中,

return restTemplate;
           

之前先請求了一次,也就是說在需要使用第三方接口調用的service層注入的時候,提前先調用了一次,根據長連接配接的特性,一般第一次連接配接的時間較長,使用完之後,這個連接配接并不會馬上回收掉,在一定的時間還是存活狀态,是以在高并發下,經過預熱後的接口響應時間會大幅提高。

(2)合理設定maxtotal數量

我們可以看到以下代碼

//設定總連接配接數
 connectionManager.setMaxTotal(maxTotal);
           

我們可以看到這一行,maxTotal是設定總連接配接數,這個設定需要根據接口的響應時間以及需要支援的QPS來設定,比如接口響應時間是100ms,需要支援的QPS為5000,也就是5000/s,那麼一個長連接配接1s就是能夠處理10個請求,那麼總共需要maxTotal為500個,這個就是設定的大概數量,但是有時候QPS不是那麼穩定,是以具體設定多少得視具體情況而定。

RestTemplate深度解析可以參考: RestTemplate深度解析

總結

以上就是關于RestTemplate的使用介紹,其實平常使用下還好,看不出來什麼問題,但是一旦高并發情況下,預熱和設定總連接配接數還有并發數以及其他的相關配置就顯得尤為重要,具體的配置還是得經過實驗才能得知,沒有最好,隻有更好,以上就是作者在高并發活動中的一些實際經曆,希望可以幫助到你!!!