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