Spring Boot 使用RestTemplate-01-使用HttpClient

簡介

  1. RestTemplate是spring支持的一個請求http rest服務的模板對象,性質上有點像jdbcTemplate
  2. 是Spring用於同步client端的核心類,簡化了與http服務的通訊,並知足RestFul原則,程序代碼能夠給它提供URL,並提取結果。默認狀況下,RestTemplate默認依賴jdk的HTTP鏈接工具。固然你也能夠 經過setRequestFactory屬性切換到不一樣的HTTP源,好比Apache HttpComponents、Netty和OkHttp。本章討論的就是設置RestTemplate底層使用的httpclient(org.apache.http.client.HttpClient)發送請求
  3. HttpClient能夠作鏈接池,而發送消息的工具類可使用RestTemplate,因此若是你的項目須要http鏈接池,RestTemplate+httpclient鏈接池是一種不錯的方式,能夠節省開發工做,也能夠更優雅的使用。

配置

  1. maven依賴
<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpclient</artifactId>
    <version>4.5.10</version>
</dependency>
 
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

2. Java配置類

java

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
 
@Component
@ConfigurationProperties(prefix = "http-pool")
@Data
public class HttpPoolProperties {
 
    private Integer maxTotal;
    private Integer defaultMaxPerRoute;
    private Integer connectTimeout;
    private Integer connectionRequestTimeout;
    private Integer socketTimeout;
    private Integer validateAfterInactivity;
 
}

import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.springframework.beans.factory.annotation.Autowired;
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.web.client.RestTemplate;
 
@Configuration
public class HttpClientRestTemplateConfig {
 
    @Autowired
    private HttpPoolProperties httpPoolProperties;
 
    @Bean("httpClientRestTemplate")
    public RestTemplate httpClientRestTemplate() {
        HttpClient httpClient = httpClient();
        ClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(httpClient);
        RestTemplate restTemplate = new RestTemplate(factory);
        // 能夠添加消息轉換
        //restTemplate.setMessageConverters(...);
        // 能夠增長攔截器
        //restTemplate.setInterceptors(...);
        return restTemplate;
    }
 
  
    @Bean
    public HttpClient httpClient() {
        Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
                .register("http", PlainConnectionSocketFactory.getSocketFactory())
                .register("https", SSLConnectionSocketFactory.getSocketFactory())
                .build();
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(registry);
// 設置整個鏈接池最大鏈接數 根據本身的場景決定
connectionManager.setMaxTotal(httpPoolProperties.getMaxTotal());

// 設置每一個路由(域名)最大的線程數
connectionManager.setDefaultMaxPerRoute(httpPoolProperties.getDefaultMaxPerRoute());

// 設置路由(域名)對應的最大線程數,若是設置則比setDefaultMaxPerRoute(xxx)的優先級高
//connectionManager.setMaxPerRoute(new HttpRoute(new HttpHost("v2.moon.com", 80)), 20);

// validateAfterInactivity 空閒永久鏈接檢查間隔,這個牽扯的還比較多,
// 官方推薦使用這個來檢查永久連接的可用性,而不推薦每次請求的時候纔去檢查
connectionManager.setValidateAfterInactivity(httpPoolProperties.getValidateAfterInactivity());

RequestConfig requestConfig = RequestConfig.custom()
        // 鏈接上服務器(握手成功)的時間(能夠設置2000),超出拋出connect timeout
        .setConnectTimeout(httpPoolProperties.getConnectTimeout()) 
        // 服務器返回數據(response)的時間(能夠設置3000),超過拋出read timeout
        .setSocketTimeout(httpPoolProperties.getSocketTimeout())
        // 從鏈接池中獲取鏈接的超時時間,超時間未拿到可用鏈接,會拋出如下異常
        //org.apache.http.conn.ConnectionPoolTimeoutException: 
        //Timeout waiting for connection from pool
        .setConnectionRequestTimeout(httpPoolProperties.getConnectionRequestTimeout())
        .build();

        // 重試一次
        DefaultHttpRequestRetryHandler requestRetryHandler = new DefaultHttpRequestRetryHandler(1, true, new ArrayList<>()) {
            public boolean retryRequest(IOException exception, int executionCount, HttpContext context) {
                LOGGER.info("Retry request, execution count: {}, exception: {}", executionCount, exception);
                return super.retryRequest(exception, executionCount, context);
            }
        };

return HttpClientBuilder.create()
        .setDefaultRequestConfig(requestConfig)
        .setConnectionManager(connectionManager)
        .setRetryHandler(requestRetryHandler)
        .build();
    }
}

3.使用方法web

import org.json.JSONException;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
 
import java.io.IOException;
 
@Service
public class TestService {
 
    @Autowired
    private RestTemplate restTemplate;
 
    public void startTest() throws JSONException, IOException {
 
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("first","jinjian");
        jsonObject.put("second","aaaaaaa");
 
        long start = System.currentTimeMillis();
        //{1} 表示第一個佔位符,也能夠填寫name,可是這是另外一個getForEntity重載方法
        //TestResponseEntity 爲自定義dto
        ResponseEntity<TestResponseEntity> entity = restTemplate.getForEntity("http://39.107.104.221/api/test/{1}", TestResponseEntity.class, 123);
        long end = System.currentTimeMillis();
        long cost = end - start;
        System.out.println("耗時:"+cost);
        RuiooResponseEntity body = entity.getBody();
        body.getData();
        body.getStatus();
        body.getMessage();
        System.out.println("響應體:"+ body);
    }
}
相關文章
相關標籤/搜索