RestTemplate线程池

配置属性类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
@Data  
@ConfigurationProperties(prefix = "sys.http.client.config")
public class HttpClientConfigProperties {
/**
* 最大连接池连接数量(n个url)
*/
private Integer poolMaxTotalConn = 400;

/**
* 最大单个路由(url)连接数量
*/
private Integer perRouterMaxConn = 100;

/**
* 连接超时时间 ms
*/ private Integer connTimeOut = 3000;

/**
* 读取超时SocketTimeOut ms
*/ private Integer connReadTimeOut = 5000;

/**
* 连接池获取请求的最大等待时间 ms
*/ private Integer poolConnReqTimeOut = 200;

/**
* 长连接保持时间 ms
*/ private Long keepAliveTime = 0L;

/**
* 配置保持长连接的域名Host
*/ private Map<String,Long> keepAliveTargetHost;

/**
* 连接默认HTTP字符集
*/
private String charSet = "UTF-8";

/**
* 支持的SSL协议
*/
private String[] supportsSslProtocol =new String[]{"SSLv3","SSLv2Hello","TLSv1","TLSv1.1","TLSv1.2"};

}

RestTemplate自定义配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
@Configuration  
@EnableConfigurationProperties({HttpClientConfigProperties.class})
@ConditionalOnClass({RestTemplate.class})
@Slf4j
public class RestTemplateConfig {

@Autowired
HttpClientConfigProperties httpClientConfigProperties;

/**
* <b>注入默认RestTemplate<b/>
* * @return RestTemplate.class
*/ @Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
/**
* <b>注入自定义连接工厂的RestTemplate<b/>
* * @return RestTemplate.class
*/ @Bean("customShuShuoRestTemplate")
public RestTemplate customRestTemplate(ClientHttpRequestFactory httpRequestFactory) {
RestTemplate restTemplate = new RestTemplate(httpRequestFactory);
//设置字符集 - 重新设置StringHttpMessageConverter字符集
List<HttpMessageConverter<?>> converterList = restTemplate.getMessageConverters();
HttpMessageConverter<?> converterTarget = null;
for (HttpMessageConverter<?> item : converterList) {
if (StringHttpMessageConverter.class == item.getClass()) {
converterTarget = item;
break;
} } if (null != converterTarget) {
converterList.remove(converterTarget);
} Charset defaultCharset = Charset.forName(httpClientConfigProperties.getCharSet());
converterList.add(1, new StringHttpMessageConverter(defaultCharset));
//设置错误处理器
restTemplate.setErrorHandler(new DefaultResponseErrorHandler());
List<ClientHttpRequestInterceptor> clientHttpRequestInterceptors = new LinkedList<>();
clientHttpRequestInterceptors.add(new HttpSendInterceptor());
restTemplate.setInterceptors(clientHttpRequestInterceptors);
return restTemplate;
}
/**
* <b>初始化HttpClient连接工厂</b>
* * @return ClientHttpRequestFactory
*/ @Bean
public ClientHttpRequestFactory clientHttpRequestFactory(HttpClient httpClient) {
//检查配置类信息
ConfigCheckUtils.checkHttpClientConfig(httpClientConfigProperties);
//初始化链接工厂,设置默认的链接对象
HttpComponentsClientHttpRequestFactory httpComponentsClientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory();
httpComponentsClientHttpRequestFactory.setHttpClient(httpClient);
//设置读取超时
httpComponentsClientHttpRequestFactory.setReadTimeout(httpClientConfigProperties.getConnReadTimeOut());
//设置从链接池获取链接超时
httpComponentsClientHttpRequestFactory.setConnectionRequestTimeout(httpClientConfigProperties.getPoolConnReqTimeOut());
//设置连接超时,与服务握手
httpComponentsClientHttpRequestFactory.setConnectTimeout(httpClientConfigProperties.getConnTimeOut());
return httpComponentsClientHttpRequestFactory;
}
/**
* 设置HTTP池化连接池
* @return 连接池
* @throws NoSuchAlgorithmException 没有这个算法
* @throws KeyStoreException 密码存储异常
* @throws KeyManagementException 密码管理器异常
*/
@Bean
public HttpClientConnectionManager poolingHttpClientConnectionManager() throws NoSuchAlgorithmException, KeyStoreException, KeyManagementException {
Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
.register("http", PlainConnectionSocketFactory.INSTANCE)
.register("https", createSslConnectionFactory())
.build();
//init httpClient Pool
PoolingHttpClientConnectionManager poolingHttpClientConnectionManager = new PoolingHttpClientConnectionManager(registry);
//配置连接池
poolingHttpClientConnectionManager.setDefaultMaxPerRoute(httpClientConfigProperties.getPerRouterMaxConn());
poolingHttpClientConnectionManager.setMaxTotal(httpClientConfigProperties.getPoolMaxTotalConn());
return poolingHttpClientConnectionManager;
}
/**
* <b>创建HTTPClient自定义对象</b>
* * @return HttpClient
*/ @Bean
public HttpClient httpClient(HttpClientConnectionManager httpClientConnectionManager) {
//init httpclient
HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();
//设置连接管理器
httpClientBuilder.setConnectionManager(httpClientConnectionManager);
//设置重试,默认没有开启
httpClientBuilder.setRetryHandler(DefaultHttpRequestRetryHandler.INSTANCE);
//设置 请求头
httpClientBuilder.setDefaultHeaders(defaultHeaders());
//设置连接策略
httpClientBuilder.setKeepAliveStrategy(connectionKeepAliveStrategy());
return httpClientBuilder.build();
}

/**
* <b>设置Http长连接处理策略</b>
* * @return ConnectionKeepAliveStrategy
*/ @Bean
public ConnectionKeepAliveStrategy connectionKeepAliveStrategy() {
return (response, context) -> {
// Honor 'keep-alive' header
HeaderElementIterator it = new BasicHeaderElementIterator(
response.headerIterator(HTTP.CONN_KEEP_ALIVE));
while (it.hasNext()) {
HeaderElement he = it.nextElement();
log.info("HeaderElement:{}", JSON.toJSONString(he));
String param = he.getName();
String value = he.getValue();
if (value != null && "timeout".equalsIgnoreCase(param)) {
try {
return Long.parseLong(value) * 1000;
} catch (NumberFormatException e) {
log.error("解析长连接过期时间异常", e);
} } } HttpHost target = (HttpHost) context.getAttribute(HttpCoreContext.HTTP_TARGET_HOST);
//如果请求Host存在配置的连接时间就用配置的,没配就是默认
Optional<Map.Entry<String, Long>> any = Optional.ofNullable(httpClientConfigProperties.getKeepAliveTargetHost()).orElseGet(HashMap::new)
.entrySet().stream().filter(
e -> e.getKey().equalsIgnoreCase(target.getHostName())).findAny();
return any.map(Map.Entry::getValue).orElse(httpClientConfigProperties.getKeepAliveTime());
}; }

/**
* <b>默认请求头</b>
* * @return List<Header> headers
*/ private List<Header> defaultHeaders() {
ArrayList<Header> headers = new ArrayList<>();
headers.add(new BasicHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.5112.81 Safari/537.36 Edg/104.0" +
".1293.54"));
headers.add(new BasicHeader("Accept-Encoding", "gzip,deflate"));
headers.add(new BasicHeader("Accept-Language", "zh-CN,en-US"));
headers.add(new BasicHeader("Connection", "Keep-Alive"));
headers.add(new BasicHeader("Content-Type", "application/json"));
return headers;
}

/**
* <b>配置绕过不安全HTTPS协议连接工厂</b>
* * @return ConnectionSocketFactory异常
* @throws NoSuchAlgorithmException 找不到指定算法
* @throws KeyManagementException 没有键值管理器异常
* @throws KeyStoreException ssl键存储吧异常
*/
private ConnectionSocketFactory createSslConnectionFactory() throws NoSuchAlgorithmException, KeyStoreException, KeyManagementException {
//init ssl上下文 加载信任证书
SSLContextBuilder sslContextBuilder = new SSLContextBuilder();
//重写TrustStrategy信任策略
sslContextBuilder.loadTrustMaterial(null, (chain, authType) -> true);
SSLContext sslContext = sslContextBuilder.build();
//create SSL connFactory
return new SSLConnectionSocketFactory(sslContext, httpClientConfigProperties.getSupportsSslProtocol(), null, SSLConnectionSocketFactory.getDefaultHostnameVerifier());
}}