Spring Boot 之 RestTemplate 連接池配置

RestTemplate 連接池配置

RestTemplate是Spring提供的用於訪問Rest服務的客戶端,RestTemplate提供了多種便捷訪問遠程Http服務的方法,能夠大大提高客戶端的編寫效率。

RestTemplate的默認連接池是 SimpleClientHttpRequestFactory

自定義連接池如下所示

配置文件類

    /**
     * RestTemplate 客戶端 Httpclient 的線程池配置
     *
     * @author fengxuechao
     * @version 0.1
     * @date 2019/11/12
     */
    @ConfigurationProperties(prefix = "http-pool")
    @Data
    public class HttpPoolProperties {
    
        /**
         * 最大線程數
         */
        private Integer maxTotal = 20;
    
        /**
         * 默認線程數
         */
        private Integer defaultMaxPerRoute = 10;
    
        /**
         * 連接上服務器(握手成功)的時間
         */
        private Integer connectTimeout = 1000;
    
        /**
         * 從連接池中獲取連接的超時時間
         */
        private Integer connectionRequestTimeout = 3000;
    
        /**
         * 服務器返回數據(response)的時間
         */
        private Integer socketTimeout = 5000;
    
        /**
         * 用於校驗線程空閒的時間
         */
        private Integer validateAfterInactivity = 7000;
    
        /**
         * 開啓異步線程池
         */
        private Boolean async = false;
    
    }

連接池配置類

忽略SSL

    /**
     * @author fengxuechao
     * @version 0.1
     * @date 2019/12/17
     */
    @Slf4j
    @Component
    public class HttpClientHelper {
    
        public SSLContext getSslContext() {
            // 在調用SSL之前需要重寫驗證方法,取消檢測SSL
            X509TrustManager trustManager = new X509TrustManager() {
                @Override
                public X509Certificate[] getAcceptedIssuers() {
                    return null;
                }
    
                @Override
                public void checkClientTrusted(X509Certificate[] xcs, String str) {
                }
    
                @Override
                public void checkServerTrusted(X509Certificate[] xcs, String str) {
                }
            };
            SSLContext ctx = null;
            try {
                ctx = SSLContext.getInstance(SSLConnectionSocketFactory.TLS);
                ctx.init(null, new TrustManager[]{trustManager}, null);
            } catch (NoSuchAlgorithmException | KeyManagementException e) {
                log.error("創建 SSL 失敗", e);
            }
            assert ctx != null;
            return ctx;
        }
    
    }

配置類

    /**
     * HttpClient 的配置
     *
     * @author fengxuechao
     * @version 0.1
     * @date 2019/11/12
     */
    @Slf4j
    @Configuration
    @ConditionalOnClass({HttpClient.class})
    @EnableConfigurationProperties(HttpPoolProperties.class)
    public class HttpClientConfig {
    
        @Autowired
        private HttpPoolProperties httpPoolProperties;
    
        @Autowired
        private HttpClientHelper helper;
    
        @Bean("httpRequestFactory")
        @ConditionalOnMissingBean
        public ClientHttpRequestFactory httpRequestFactory() {
            return new HttpComponentsClientHttpRequestFactory(httpClient());
        }
    
        @Bean("httpClient")
        @ConditionalOnMissingBean
        public HttpClient httpClient() {
            // 在調用SSL之前需要重寫驗證方法,取消檢測SSL
            X509TrustManager trustManager = new X509TrustManager() {
                @Override public X509Certificate[] getAcceptedIssuers() {
                    return null;
                }
                @Override public void checkClientTrusted(X509Certificate[] xcs, String str) {}
                @Override public void checkServerTrusted(X509Certificate[] xcs, String str) {}
            };
            SSLConnectionSocketFactory socketFactory = null;
            try {
                SSLContext ctx = helper.getSslContext();
                ctx.init(null, new TrustManager[] { trustManager }, null);
                socketFactory = new SSLConnectionSocketFactory(ctx, NoopHostnameVerifier.INSTANCE);
            } catch (KeyManagementException e) {
                log.error("創建 SSL 失敗", e);
            }
    
            assert socketFactory != null;
            Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
                    .register("http", PlainConnectionSocketFactory.getSocketFactory())
                    .register("https", socketFactory)
                    .build();
            PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(registry);
            connectionManager.setMaxTotal(httpPoolProperties.getMaxTotal());
            connectionManager.setDefaultMaxPerRoute(httpPoolProperties.getDefaultMaxPerRoute());
            connectionManager.setValidateAfterInactivity(httpPoolProperties.getValidateAfterInactivity());
            RequestConfig requestConfig = RequestConfig.custom()
                    //服務器返回數據(response)的時間,超過拋出read timeout
                    .setSocketTimeout(httpPoolProperties.getSocketTimeout())
                    //連接上服務器(握手成功)的時間,超出拋出connect timeout
                    .setConnectTimeout(httpPoolProperties.getConnectTimeout())
                    //從連接池中獲取連接的超時時間,超時間未拿到可用連接,會拋出org.apache.http.conn.ConnectionPoolTimeoutException: Timeout waiting for connection from pool
                    .setConnectionRequestTimeout(httpPoolProperties.getConnectionRequestTimeout())
                    .build();
            return HttpClientBuilder.create()
                    .setDefaultRequestConfig(requestConfig)
                    .setConnectionManager(connectionManager)
                    .build();
        }
    }

RestTemplate 配置

    /**
     * @author fengxuechao
     * @version 0.1
     * @date 2019/11/12
     */
    @Configuration
    @Import({HttpClientConfig.class})
    public class RestTemplateConfiguration {
    
        /**
         * 普通的 RestTemplate
         *
         * @return
         */
        @Bean("restTemplate")
        @ConditionalOnMissingBean
        @ConditionalOnBean(value = ClientHttpRequestFactory.class)
        public RestTemplate restTemplate(ClientHttpRequestFactory httpRequestFactory) {
            RestTemplate restTemplate = new RestTemplate(httpRequestFactory);
            restTemplate.getMessageConverters().set(1, new StringHttpMessageConverter(StandardCharsets.UTF_8));
            return restTemplate;
        }
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章