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);
    }

}

具体大小适状况而定. 链接总数配置过大还会影响性能.网站

相关文章
相关标签/搜索