溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

springboot restTemplate連接池整合方式是什么

發布時間:2021-10-23 13:36:32 來源:億速云 閱讀:249 作者:iii 欄目:開發技術

本篇內容主要講解“springboot restTemplate連接池整合方式是什么”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“springboot restTemplate連接池整合方式是什么”吧!

目錄
  • springboot restTemplate連接池整合

    • restTemplate

    • 引入apache httpclient

    • RestTemplate配置類

    • RestTemplate連接池配置參數

    • 測試帶連接池的RestTemplate

  • RestTemplate 配置http連接池

    springboot restTemplate連接池整合

    restTemplate

    使用http連接池能夠減少連接建立與釋放的時間,提升http請求的性能。如果客戶端每次請求都要和服務端建立新的連接,即三次握手將會非常耗時。本文介紹如何在Springboot中集成http連接池;基于restTemplate+httpclient實現。

    引入apache httpclient

    <dependency>
                <groupId>org.apache.httpcomponents</groupId>
                <artifactId>httpclient</artifactId>
                <version>4.5.6</version>
            </dependency>

    RestTemplate配置類

    import org.apache.http.client.HttpClient;
    import org.apache.http.impl.client.HttpClientBuilder;
    import org.springframework.boot.context.properties.ConfigurationProperties;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.http.client.ClientHttpRequestFactory;
    import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
    import org.springframework.http.client.SimpleClientHttpRequestFactory;
    import org.springframework.http.converter.HttpMessageConverter;
    import org.springframework.http.converter.StringHttpMessageConverter;
    import org.springframework.web.client.RestTemplate;
    import java.nio.charset.Charset;
    import java.util.List;
    import java.util.concurrent.TimeUnit;
    /**
     * 實際開發中要避免每次http請求都實例化httpclient
     * restTemplate默認會復用連接,保證restTemplate單例即可
     * 參考資料:
     * https://www.cnblogs.com/xrq730/p/10963689.html
     * https://halfrost.com/advance_tcp/
     */
    @Configuration
    public class RestTemplateConfig {
        @Bean
        RestTemplate restTemplate(ClientHttpRequestFactory clientHttpRequestFactory) {
            RestTemplate restTemplate = new RestTemplate(clientHttpRequestFactory);
            List<HttpMessageConverter<?>> messageConverters = restTemplate.getMessageConverters();
            for (HttpMessageConverter c : messageConverters) {
                if (c instanceof StringHttpMessageConverter) {
                    ((StringHttpMessageConverter) c).setDefaultCharset(Charset.forName("utf-8"));
                }
            }
            return restTemplate;
        }
        @Bean
        @ConfigurationProperties(prefix = "spring.resttemplate")
        HttpClientProperties httpClientProperties() {
            return new HttpClientProperties();
        }
        @Bean
        ClientHttpRequestFactory clientHttpRequestFactory(HttpClientProperties httpClientProperties) {
            //如果不使用HttpClient的連接池,則使用restTemplate默認的SimpleClientHttpRequestFactory,底層基于HttpURLConnection
            if (!httpClientProperties.isUseHttpClientPool()) {
                SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
                factory.setConnectTimeout(httpClientProperties.getConnectTimeout());
                factory.setReadTimeout(httpClientProperties.getReadTimeout());
                return factory;
            }
            //HttpClient4.3及以上版本不手動設置HttpClientConnectionManager,默認就會使用連接池PoolingHttpClientConnectionManager
            HttpClient httpClient = HttpClientBuilder.create().setMaxConnTotal(httpClientProperties.getMaxTotalConnect())
                    .setMaxConnPerRoute(httpClientProperties.getMaxConnectPerRoute()).evictExpiredConnections()
                    .evictIdleConnections(5000, TimeUnit.MILLISECONDS).build();
            HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(httpClient);
            factory.setConnectTimeout(httpClientProperties.getConnectTimeout());
            factory.setReadTimeout(httpClientProperties.getReadTimeout());
            factory.setConnectionRequestTimeout(httpClientProperties.getConnectionRequestTimeout());
            return factory;
        }
    }

    RestTemplate連接池配置參數

    public class HttpClientProperties {
        /**
         * 是否使用httpclient連接池
         */
        private boolean useHttpClientPool = false;
        /**
         * 從連接池中獲得一個connection的超時時間
         */
        private int connectionRequestTimeout = 3000;
        /**
         * 建立連接超時時間
         */
        private int connectTimeout = 3000;
        /**
         * 建立連接后讀取返回數據的超時時間
         */
        private int readTimeout = 5000;
        /**
         * 連接池的最大連接數,0代表不限
         */
        private int maxTotalConnect = 128;
        /**
         * 每個路由的最大連接數
         */
        private int maxConnectPerRoute = 32;
        public int getConnectionRequestTimeout() {
            return connectionRequestTimeout;
        }
        public void setConnectionRequestTimeout(int connectionRequestTimeout) {
            this.connectionRequestTimeout = connectionRequestTimeout;
        }
        public int getConnectTimeout() {
            return connectTimeout;
        }
        public void setConnectTimeout(int connectTimeout) {
            this.connectTimeout = connectTimeout;
        }
        public int getReadTimeout() {
            return readTimeout;
        }
        public void setReadTimeout(int readTimeout) {
            this.readTimeout = readTimeout;
        }
        public int getMaxTotalConnect() {
            return maxTotalConnect;
        }
        public void setMaxTotalConnect(int maxTotalConnect) {
            this.maxTotalConnect = maxTotalConnect;
        }
        public int getMaxConnectPerRoute() {
            return maxConnectPerRoute;
        }
        public void setMaxConnectPerRoute(int maxConnectPerRoute) {
            this.maxConnectPerRoute = maxConnectPerRoute;
        }
        public boolean isUseHttpClientPool() {
            return useHttpClientPool;
        }
        public void setUseHttpClientPool(boolean useHttpClientPool) {
            this.useHttpClientPool = useHttpClientPool;
        }
    }

    application.properties

    spring.resttemplate.connectionRequestTimeout=3000
    spring.resttemplate.connectTimeout=3000
    spring.resttemplate.readTimeout=10000
    spring.resttemplate.maxTotalConnect=256
    spring.resttemplate.maxConnectPerRoute=128
    spring.resttemplate.useHttpClientPool=true

    測試帶連接池的RestTemplate

    import com.alibaba.fastjson.JSON;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.test.context.SpringBootTest;
    import org.springframework.http.HttpEntity;
    import org.springframework.http.HttpHeaders;
    import org.springframework.http.HttpMethod;
    import org.springframework.http.ResponseEntity;
    import org.springframework.test.context.junit4.SpringRunner;
    import org.springframework.web.client.RestTemplate;
    import org.springframework.web.util.UriComponentsBuilder;
    import java.util.Arrays;
    import java.util.List;
    import java.util.concurrent.ThreadLocalRandom;
    @RunWith(SpringRunner.class)
    @SpringBootTest
    public class RestTemplateTest {
        /**
         * 免費查詢號碼歸屬地接口
         */
        public String testUrl = "https://tcc.taobao.com/cc/json/mobile_tel_segment.htm";
        @Autowired
        RestTemplate restTemplate;
        @Test
        public void testRest() {
            HttpHeaders headers = new HttpHeaders();
            headers.set("Accept", "application/json");
            HttpEntity entity = new HttpEntity(headers);
            long start = System.currentTimeMillis();
            for (int i = 0; i < 1000; i++) {
                String tel = getRandomTel();
                UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(testUrl).queryParam("tel", tel);
                System.out.println("發送請求:" + builder.build().encode().toUri());
                long startInner = System.currentTimeMillis();
                ResponseEntity<String> getDistrictRes = restTemplate.exchange(builder.build().encode().toUri(), HttpMethod.GET, entity, String.class);
                long endInner = System.currentTimeMillis();
                System.out.print("costPerRequest:" + (endInner - startInner) + ",i=" + i + "," + Thread.currentThread().getName());
                String resJson = getDistrictRes.getBody().split("=")[1];
                String carrier = (String) JSON.parseObject(resJson).get("carrier");
                System.out.println("," + tel + ",歸屬地:" + carrier);
            }
            long end = System.currentTimeMillis();
            System.out.println("costTotal:" + (end - start));
        }
        private String getRandomTel() {
            List<String> telList = Arrays.asList("18120168516", "15952044278", "15537788259", "18751872329", "13913329187");
            int index = ThreadLocalRandom.current().nextInt(telList.size());
            return telList.get(index);
        }
    }

    測試比較發現,如果不設置ClientHttpRequestFactory,resttemplate默認會使用SimpleClientHttpRequestFactory,底層基于HttpURLConnection;這種方式和手動設置帶連接池的httpComponentsClientHttpRequestFactory性能差別不大,基于httpclient的連接池性能稍有優勢,不是太明顯。

    不管是使用restTemplate默認的SimpleClientHttpRequestFactory還是使用httpclient提供的HttpComponentsClientHttpRequestFactory,都會進行連接復用,即只有第一次請求耗時較高,后面的請求都復用連接。

    使用httpclient可以設置evictExpiredConnections、evictIdleConnections進行定時清理過期、閑置連接。底層是開啟了一個線程去執行清理任務,因此注意不能多次實例化httpclient相關的實例,會導致不斷創建線程。

    注意事項

    實際開發中要避免每次http請求都實例化httpclient

    restTemplate默認會復用連接,保證restTemplate單例即

    RestTemplate 配置http連接池

    import java.nio.charset.Charset;
    import java.util.Iterator;
    import java.util.List;
    import org.apache.http.client.HttpClient;
    import org.apache.http.conn.HttpClientConnectionManager;
    import org.apache.http.impl.client.HttpClientBuilder;
    import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
    import org.springframework.boot.web.client.RestTemplateBuilder;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.http.client.ClientHttpRequestFactory;
    import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
    import org.springframework.http.converter.HttpMessageConverter;
    import org.springframework.http.converter.StringHttpMessageConverter;
    import org.springframework.web.client.RestTemplate;
     
    @Configuration
    public class RestTemplateUtil{ 
        @Bean
        public RestTemplate restTemplate(RestTemplateBuilder builder) {
    	RestTemplate restTemplate = builder.build();
    	restTemplate.setRequestFactory(clientHttpRequestFactory()); 
            // 使用 utf-8 編碼集的 conver 替換默認的 conver(默認的 string conver 的編碼集為"ISO-8859-1")
            List<HttpMessageConverter<?>> messageConverters = restTemplate.getMessageConverters();
            Iterator<HttpMessageConverter<?>> iterator = messageConverters.iterator();
            while (iterator.hasNext()) {
                HttpMessageConverter<?> converter = iterator.next();
                if (converter instanceof StringHttpMessageConverter) {
                    iterator.remove();
                }
            }
            messageConverters.add(new StringHttpMessageConverter(Charset.forName("UTF-8"))); 
            return restTemplate;
        }	
        
        @Bean
        public HttpClientConnectionManager poolingConnectionManager() {
    	PoolingHttpClientConnectionManager poolingConnectionManager = new PoolingHttpClientConnectionManager();
    	poolingConnectionManager.setMaxTotal(1000); // 連接池最大連接數  
    	poolingConnectionManager.setDefaultMaxPerRoute(100); // 每個主機的并發
    	return poolingConnectionManager;
        }
        
        @Bean
        public HttpClientBuilder httpClientBuilder() {
    	HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();
            //設置HTTP連接管理器
    	httpClientBuilder.setConnectionManager(poolingConnectionManager());
    	return httpClientBuilder;
        }
        
        @Bean
        public ClientHttpRequestFactory clientHttpRequestFactory() { 
    	HttpComponentsClientHttpRequestFactory clientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory();
    	clientHttpRequestFactory.setHttpClient(httpClientBuilder().build());
    	clientHttpRequestFactory.setConnectTimeout(6000); // 連接超時,毫秒		
    	clientHttpRequestFactory.setReadTimeout(6000); // 讀寫超時,毫秒		
    	return clientHttpRequestFactory;
        }
    }

    到此,相信大家對“springboot restTemplate連接池整合方式是什么”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!

    向AI問一下細節

    免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

    AI

    亚洲午夜精品一区二区_中文无码日韩欧免_久久香蕉精品视频_欧美主播一区二区三区美女