1.对外部第三方服务调用,使用RestTemplate最为方便快捷
@Slf4j
@Configuration
public class RestTemplateConfig {
//最大连接数
@Value("${RestTemplateHttp.maxTotal:200}")
private Integer maxTotal;
//并发数
@Value("${RestTemplateHttp.defaultMaxPerRoute:200}")
private Integer defaultMaxPerRoute;
//创建连接的最长时间
@Value("${RestTemplateHttp.connectTimeout:15000}")
private Integer connectTimeout;
//从连接池中获取到连接的最长时间
@Value("${RestTemplateHttp.connectionRequestTimeout:30000}")
private Integer connectionRequestTimeout;
//数据传输的最长时间
@Value("${RestTemplateHttp.socketTimeout:30000}")
private Integer socketTimeout;
//可用空闲连接过期时间,重用空闲连接时会先检查是否空闲时间超过这个时间,如果超过,释放socket重新建立
@Value("${RestTemplateHttp.validateAfterInactivity:10000}")
private Integer validateAfterInactivity;
@Autowired
private TokenRequestInterceptor requestInterceptor;
@Bean
@Primary
public RestTemplate restTemplate() {
return new RestTemplate(httpRequestFactory());
}
/**
* 只用于 {@link BaseClientApi}
* @return
*/
@Bean("baseApiRestTemplate")
public RestTemplate baseApiRestTemplate() {
RestTemplate restTemplate = new RestTemplate(httpRequestFactory());
restTemplate.setInterceptors(Arrays.asList(requestInterceptor));
/* //换上fastjson
List> messageConverters= restTemplate.getMessageConverters();
Iterator> iterator=messageConverters.iterator();
while(iterator.hasNext()){
HttpMessageConverter> converter=iterator.next();
//原有的String是ISO-8859-1编码 去掉
if(converter instanceof StringHttpMessageConverter){
iterator.remove();
}
//由于系统中默认有jackson 在转换json时自动会启用 但是我们不想使用它 可以直接移除
if(converter instanceof GsonHttpMessageConverter || converter instanceof MappingJackson2HttpMessageConverter){
iterator.remove();
}
}
messageConverters.add(new StringHttpMessageConverter(Charset.forName("utf-8")));
FastJsonHttpMessageConverter fastJsonHttpMessageConverter = new FastJsonHttpMessageConverter();
List mediaTypes = new ArrayList<>(16);
mediaTypes.add(MediaType.APPLICATION_JSON);
mediaTypes.add(MediaType.APPLICATION_ATOM_XML);
mediaTypes.add(MediaType.APPLICATION_FORM_URLENCODED);
mediaTypes.add(MediaType.APPLICATION_OCTET_STREAM);
fastJsonHttpMessageConverter.setSupportedMediaTypes(mediaTypes);
FastJsonConfig fastJsonConfig = new FastJsonConfig();
fastJsonConfig.setSerializerFeatures(
SerializerFeature.QuoteFieldNames,
SerializerFeature.WriteMapNullValue,
SerializerFeature.WriteNullListAsEmpty,
SerializerFeature.WriteNullNumberAsZero,
SerializerFeature.WriteNullBooleanAsFalse,
SerializerFeature.WriteNullStringAsEmpty,
SerializerFeature.BrowserCompatible,
SerializerFeature.BrowserCompatible,
SerializerFeature.WriteSlashAsSpecial,
SerializerFeature.WriteDateUseDateFormat,
SerializerFeature.DisableCircularReferenceDetect);
fastJsonHttpMessageConverter.setFastJsonConfig(fastJsonConfig);
messageConverters.add(fastJsonHttpMessageConverter);*/
return restTemplate;
}
@Bean
public ClientHttpRequestFactory httpRequestFactory() {
return new HttpComponentsClientHttpRequestFactory(httpClient());
}
@Bean
public HttpClient httpClient() {
Registry registry = RegistryBuilder.create()
.register("http", PlainConnectionSocketFactory.getSocketFactory())
.register("https", SSLConnectionSocketFactory.getSocketFactory())
.build();
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(registry);
connectionManager.setMaxTotal(maxTotal); // 最大连接数
connectionManager.setDefaultMaxPerRoute(defaultMaxPerRoute); //单个路由最大连接数
connectionManager.setValidateAfterInactivity(validateAfterInactivity); // 最大空间时间
RequestConfig requestConfig = RequestConfig.custom()
.setSocketTimeout(socketTimeout) //服务器返回数据(response)的时间,超过抛出read timeout
.setConnectTimeout(connectTimeout) //连接上服务器(握手成功)的时间,超出抛出connect timeout
.setConnectionRequestTimeout(connectionRequestTimeout)//从连接池中获取连接的超时时间,超时间未拿到可用连接,会抛出org.apache.http.conn.ConnectionPoolTimeoutException: Timeout waiting for connection from pool
.build();
return HttpClientBuilder.create()
.setRetryHandler((exception, executionCount, context) -> {
if (executionCount > 3) {
log.warn("Maximum tries reached for client http pool ");
return false;
}
if (exception instanceof NoHttpResponseException //NoHttpResponseException 重试
|| exception instanceof ConnectTimeoutException //连接超时重试
|| exception instanceof SocketTimeoutException //响应超时不重试,避免造成业务数据不一致
) {
log.warn("NoHttpResponseException on " + executionCount + " call");
return true;
}
return false;
})
.setDefaultRequestConfig(requestConfig)
.setConnectionManager(connectionManager)
.build();
}
}
2.对微服务之间使用fegin接口调用,使用OKhttp代替HttpClient,OKhttp可以灵活设置长链接的超时时间等参数
@Configuration
@ConditionalOnClass(Feign.class)
@AutoConfigureBefore(FeignAutoConfiguration.class)
public class FeignOkHttpConfig {
@Value("${httpclient.connect-timeout-seconds: 1}")
private int connectTimeoutSeconds;
@Value("${httpclient.read-timeout-seconds: 1}")
private int readTimeoutSeconds;
@Value("${httpclient.write-timeout-seconds: 1}")
private int writeTimeoutSeconds;
@Value("${httpclient.connection-pool.max-idle: 100}")
private int maxIdle;;
@Value("${httpclient.connection-pool.keep-alive-duration-seconds: 300}")
private int keepAliveDurationSeconds;;
@Bean
public okhttp3.OkHttpClient okHttpClient() {
return new okhttp3.OkHttpClient.Builder()
.readTimeout(readTimeoutSeconds, TimeUnit.SECONDS)
.connectTimeout(connectTimeoutSeconds, TimeUnit.SECONDS)
.writeTimeout(writeTimeoutSeconds, TimeUnit.SECONDS)
.connectionPool(new ConnectionPool(maxIdle, keepAliveDurationSeconds, TimeUnit.SECONDS))
.build();
}
}