Spring RestTemplate 超時設置 和 ResourceAccessException

概述

超級簡單易用的 Spring RestTemplate, 還能夠多線程共享一個實例, 有一個小缺憾, 就是須要記得設置默認超時時間, 不然默認不超時. 而設置超時時間之後, 又會引入新的 Connection Pool 大小的問題.java

設置超時

這個連接講了兩種方式:spring-resttemplate-timeout, 這裏就直接貼過來了web

方式1

@Configuration
public class AppConfig{
    @Bean
    public RestTemplate customRestTemplate(){
        HttpComponentsClientHttpRequestFactory httpRequestFactory = new HttpComponentsClientHttpRequestFactory();
        httpRequestFactory.setConnectionRequestTimeout(...);
        httpRequestFactory.setConnectTimeout(...);
        httpRequestFactory.setReadTimeout(...);

        return new RestTemplate(httpRequestFactory);
    }
}

方式2

@Bean
public RestTemplate restTemplate(
        RestTemplateBuilder restTemplateBuilder) {

    return restTemplateBuilder
            .setConnectTimeout(500)
            .setReadTimeout(500)
            .build();
}

方式3

(不建議) 之前見過, 經過 property 設置全局 java.net 裏 URL 的 timeout 來影響 RestTemplate 的超時時間(默認使用java.net包裏面組件).spring

設置超時後問題和解決

調用 RestTemplate 的默認構造函數,RestTemplate 對象在底層經過使用 java.net 包下的實現建立 HTTP 請求. 這種狀況相對簡單, 一個請求一個鏈接, 也沒有限制.多線程

而上面所說的前兩種設置超時方式, 都會致使 RestTemplate 引入 Apache HttpClient 去設置超時時間. 在默認 HttpClientBuilder (httpClient-4.5.2)裏面有一段代碼:app

if (systemProperties) {
    String s = System.getProperty("http.keepAlive", "true");
    if ("true".equalsIgnoreCase(s)) {
        s = System.getProperty("http.maxConnections", "5");
        final int max = Integer.parseInt(s);
        poolingmgr.setDefaultMaxPerRoute(max);
        poolingmgr.setMaxTotal(2 * max);
    }
}

在 keepAlive(默認) 狀況下, 默認設置了對單個 host 的最大 connection 數量是 5. 全部connection數量不能超過 10~ 若是說單個 host 設置長鏈接數設置爲5問題不大的話, 那麼對於須要訪問多個不一樣網站的狀況下, 鏈接總數一共10個就有點坑了. 在長時間得不到Connection的狀況下, 會拋出異常: org.springframework.web.client.ResourceAccessException Timeout waiting for connection from pool函數

具體解決方法是手工配置一下鏈接池:性能

@Configuration
public class RestTemplateConfig {

    @Value("${application.http.resttemplate.timeoutSeconds:30}")
    private Integer defaultTimeOutSeconds;

    @Value("${application.http.resttemplate.maxConnPerRoute:50}")
    private Integer defaultMaxPerRoute;

    @Value("${application.http.resttemplate.maxConnTotal:200}")
    private Integer maxTotal;

    @Bean
    public RestTemplate customRestTemplate() {

        int timeoutMills = defaultTimeOutSeconds * 1000;

        RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(timeoutMills)
                .setConnectionRequestTimeout(timeoutMills).setSocketTimeout(timeoutMills).build();

        HttpClient httpClient = HttpClientBuilder.create().setMaxConnTotal(maxTotal)
                .setMaxConnPerRoute(defaultMaxPerRoute).setDefaultRequestConfig(requestConfig).build();

        HttpComponentsClientHttpRequestFactory httpRequestFactory = new HttpComponentsClientHttpRequestFactory(
                httpClient);

        return new RestTemplate(httpRequestFactory);
    }

}

具體大小適狀況而定. 鏈接總數配置過大還會影響性能.網站

相關文章
相關標籤/搜索