Fork me on GitHub

Spring Boot之RestTemplate发送HTTPS以及线程池配置

因现在微服务项目多,服务之间接口调用也用的多,加上每次写项目都的弄次这HTTPS的配置东东,今天没事记录下来。

POM配置

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpclient</artifactId>
    <version>4.5.3</version>
</dependency>
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <optional>true</optional>
</dependency>

新建类RestTemplateConfig


import com.icodesoft.demo.util.SslUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.Header;
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.CloseableHttpClient;
import org.apache.http.impl.client.DefaultHttpRequestRetryHandler;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicHeader;
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;

import java.util.ArrayList;
import java.util.List;

@Slf4j
@Configuration
public class RestTemplateConfig {

    @Autowired
    private HttpClientPoolConfig poolConfig;

    @Bean(name = "sslRestTemplate")
    public RestTemplate restTemplate(ClientHttpRequestFactory factory){
        return new RestTemplate(factory);
    }

    @Bean
    public ClientHttpRequestFactory httpRequestFactory() {
        CloseableHttpClient httpClient = getCloseableHttpClient();

        HttpComponentsClientHttpRequestFactory httpComponentsClientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory();
        httpComponentsClientHttpRequestFactory.setHttpClient(httpClient);
 httpComponentsClientHttpRequestFactory.setConnectionRequestTimeout(poolConfig.getConnectionRequestTimeout()); // 不宜过长
 httpComponentsClientHttpRequestFactory.setConnectTimeout(poolConfig.getConnectionTimeout());
 httpComponentsClientHttpRequestFactory.setReadTimeout(poolConfig.getSocketTimeout());


        return httpComponentsClientHttpRequestFactory;
    }

    private CloseableHttpClient getCloseableHttpClient() {
        SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(SslUtil.getSslContext(), SslUtil.getHostnameVerifier());
        Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
                .register("http", PlainConnectionSocketFactory.getSocketFactory())
                .register("https", sslConnectionSocketFactory)
                .build();
        PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(registry);

        // 连接池最大连接数
        connectionManager.setMaxTotal(poolConfig.getMaxTotal());

        // 同路由并发数
        connectionManager.setDefaultMaxPerRoute(poolConfig.getMaxPerRoute());

        CloseableHttpClient httpClient = HttpClients.custom()
                .setSSLSocketFactory(sslConnectionSocketFactory)
                .setConnectionManager(connectionManager)
                .setRetryHandler(new DefaultHttpRequestRetryHandler(poolConfig.getRetryTimes(), true))
                .setDefaultHeaders(defaultHeaders())
                .build();
        return httpClient;
    }

    private List<Header> defaultHeaders() {
        List<Header> headers = new ArrayList<>();
        headers.add(new BasicHeader("Accept", "*/*"));
        headers.add(new BasicHeader("Content-Type", "application/json"));
        return headers;
    }
}

添加HTTP线程池配置类 HttpClientPoolConfig


import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;

@Configuration
public class HttpClientPoolConfig {

    @Value("${http-pool.connection-request-timeout}")
    private  int connectionRequestTimeout;

    // 连接超时
    @Value("${http-pool.connection-timeout}")
    private  int connectionTimeout;

    // 数据读取超时时间
    @Value("${http-pool.socket-timeout}")
    private  int socketTimeout;

    // 同路由并发数
    @Value("${http-pool.max-per-route}")
    private  int maxPerRoute;

    // 池最大数
    @Value("${http-pool.max-total}")
    private  int maxTotal;

    // 重试次数
    @Value("${http-pool.retry-times}")
    private int retryTimes;

    public int getRetryTimes() {
        return retryTimes;
    }

    public int getConnectionRequestTimeout() {
        return connectionRequestTimeout;
    }

    public int getConnectionTimeout() {
        return connectionTimeout;
    }

    public int getSocketTimeout() {
        return socketTimeout;
    }

    public int getMaxPerRoute() {
        return maxPerRoute;
    }

    public int getMaxTotal() {
        return maxTotal;
    }
}

工具类SslUtil

@Slf4j
public class SslUtil {

    public static HostnameVerifier getHostnameVerifier() {
        HostnameVerifier hostnameVerifier = NoopHostnameVerifier.INSTANCE;
        return hostnameVerifier;
    }

    public static SSLContext getSslContext() {
        SSLContext sslContext = null;
        try {
            sslContext = new SSLContextBuilder().loadTrustMaterial(null, (arg0, arg1) -> true).build();
        } catch (NoSuchAlgorithmException | KeyManagementException | KeyStoreException exception) {
            log.error("初始化SSLContext出错", exception);
        }
        return sslContext;
    }
}

application.yaml配置

http-pool:
  # 从连接池获取连接的timeout,不宜过大,ms
  connection-request-timeout: 100
  connection-timeout: 10000
  socket-timeout: 10000
  # 每个路由的最大连接数,如果只调用一个地址,可以将其设置为最大连接数
  max-per-route: 100
  # 连接池的最大连接数,0代表不限
  max-total: 1000
  retry-times: 3

应用

注意这儿的注解(@Resource)以及变量名 sslRestTemplate

 @Resource
 private RestTemplate sslRestTemplate;

 @GetMapping("/test")
 public ResponseResult<String> test() throws Exception {
    String url = "https://testservice/api/classinfo";
    ResponseEntity<String> forEntity = sslRestTemplate.getForEntity(url, String.class);
    return ok(forEntity.getBody());
 }

发送HTTP请求查看结果http://localhost:8080/api/test

posted @ 2022-08-26 16:59  逍遥メ风  阅读(1640)  评论(0编辑  收藏  举报