package com.xncoding.pos.config; import com.xncoding.pos.config.properties.HttpClientProperties; import org.apache.http.HeaderElement; import org.apache.http.HeaderElementIterator; import org.apache.http.HttpResponse; import org.apache.http.client.config.RequestConfig; import org.apache.http.config.Registry; import org.apache.http.config.RegistryBuilder; import org.apache.http.conn.ConnectionKeepAliveStrategy; 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.conn.ssl.TrustStrategy; 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.BasicHeaderElementIterator; import org.apache.http.protocol.HTTP; import org.apache.http.protocol.HttpContext; import org.apache.http.ssl.SSLContextBuilder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.scheduling.TaskScheduler; import org.springframework.scheduling.annotation.EnableScheduling; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; import javax.annotation.Resource; import java.security.KeyManagementException; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.cert.X509Certificate; import java.util.concurrent.TimeUnit; /** * - Supports both HTTP and HTTPS * - Uses a connection pool to re-use connections and save overhead of creating connections. * - Has a custom connection keep-alive strategy (to apply a default keep-alive if one isn't specified) * - Starts an idle connection monitor to continuously clean up stale connections. * * @author XiongNeng * @version 1.0 * @since 2018/7/5 */ @Configuration @EnableScheduling public class HttpClientConfig { private static final Logger LOGGER = LoggerFactory.getLogger(HttpClientConfig.class); @Resource private HttpClientProperties p; @Bean public PoolingHttpClientConnectionManager poolingConnectionManager() { SSLContextBuilder builder = new SSLContextBuilder(); try { builder.loadTrustMaterial(null, new TrustStrategy() { public boolean isTrusted(X509Certificate[] arg0, String arg1) { return true; } }); } catch (NoSuchAlgorithmException | KeyStoreException e) { LOGGER.error("Pooling Connection Manager Initialisation failure because of " + e.getMessage(), e); } SSLConnectionSocketFactory sslsf = null; try { sslsf = new SSLConnectionSocketFactory(builder.build()); } catch (KeyManagementException | NoSuchAlgorithmException e) { LOGGER.error("Pooling Connection Manager Initialisation failure because of " + e.getMessage(), e); } Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder .<ConnectionSocketFactory>create() .register("https", sslsf) .register("http", new PlainConnectionSocketFactory()) .build(); PoolingHttpClientConnectionManager poolingConnectionManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry); poolingConnectionManager.setMaxTotal(p.getMaxTotalConnections()); //最大连接数 poolingConnectionManager.setDefaultMaxPerRoute(p.getDefaultMaxPerRoute()); //同路由并发数 return poolingConnectionManager; } @Bean public ConnectionKeepAliveStrategy connectionKeepAliveStrategy() { return new ConnectionKeepAliveStrategy() { @Override public long getKeepAliveDuration(HttpResponse response, HttpContext httpContext) { HeaderElementIterator it = new BasicHeaderElementIterator (response.headerIterator(HTTP.CONN_KEEP_ALIVE)); while (it.hasNext()) { HeaderElement he = it.nextElement(); String param = he.getName(); String value = he.getValue(); if (value != null && param.equalsIgnoreCase("timeout")) { return Long.parseLong(value) * 1000; } } return p.getDefaultKeepAliveTimeMillis(); } }; } @Bean public CloseableHttpClient httpClient() { RequestConfig requestConfig = RequestConfig.custom() .setConnectionRequestTimeout(p.getRequestTimeout()) .setConnectTimeout(p.getConnectTimeout()) .setSocketTimeout(p.getSocketTimeout()).build(); return HttpClients.custom() .setDefaultRequestConfig(requestConfig) .setConnectionManager(poolingConnectionManager()) .setKeepAliveStrategy(connectionKeepAliveStrategy()) .setRetryHandler(new DefaultHttpRequestRetryHandler(3, true)) // 重试次数 .build(); } @Bean public Runnable idleConnectionMonitor(final PoolingHttpClientConnectionManager connectionManager) { return new Runnable() { @Override @Scheduled(fixedDelay = 10000) public void run() { try { if (connectionManager != null) { LOGGER.trace("run IdleConnectionMonitor - Closing expired and idle connections..."); connectionManager.closeExpiredConnections(); connectionManager.closeIdleConnections(p.getCloseIdleConnectionWaitTimeSecs(), TimeUnit.SECONDS); } else { LOGGER.trace("run IdleConnectionMonitor - Http Client Connection manager is not initialised"); } } catch (Exception e) { LOGGER.error("run IdleConnectionMonitor - Exception occurred. msg={}, e={}", e.getMessage(), e); } } }; } @Bean public TaskScheduler taskScheduler() { ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler(); scheduler.setThreadNamePrefix("poolScheduler"); scheduler.setPoolSize(50); return scheduler; } }