import lombok.extern.slf4j.Slf4j;
import org.apache.http.Header;
import org.apache.http.client.config.CookieSpecs;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.HttpRequestBase;
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.LayeredConnectionSocketFactory;
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.HttpClients;
import org.apache.http.impl.client.LaxRedirectStrategy;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import javax.net.ssl.SSLContext;
import java.security.NoSuchAlgorithmException;
import java.util.TimerTask;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* http链接管理器
* @author terry
* @date 2019-2-27 9:04
*/
@Slf4j
@Component
public class HttpConnectionManager {
/** 最大链接数 **/
private static final int MAX_TOTAL = 2000;
/** 每个路由的最大链接数 **/
private static final int MAX_PER_ROUTE = 1000;
/** 读取响应的超时时间 **/
private static final int SOCKET_TIME_OUT = 10000;
/** 建立链接的超时时间 **/
private static final int CONNECT_TIME_OUT = 6000;
/** 从链接池中获取链接的等待超时时间 **/
private static final int REQUEST_TIME_OUT = 5000;
private static PoolingHttpClientConnectionManager connectionManager;
private static ScheduledExecutorService monitorExecutor;
private static LayeredConnectionSocketFactory socketFactory;
private static CloseableHttpClient closeableHttpClient;
@PostConstruct
public void init(){
try {
socketFactory = new SSLConnectionSocketFactory(SSLContext.getDefault());
} catch (NoSuchAlgorithmException e) {
log.warn("init SSLConnectionSocketFactory failed.", e);
}
RegistryBuilder<ConnectionSocketFactory> registryBuilder = RegistryBuilder.<ConnectionSocketFactory> create();
if (null != socketFactory){
registryBuilder.register("https", socketFactory);
}
Registry<ConnectionSocketFactory> socketFactoryRegistry = registryBuilder
.register("http", new PlainConnectionSocketFactory())
.build();
connectionManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
connectionManager.setMaxTotal(MAX_TOTAL);
connectionManager.setDefaultMaxPerRoute(MAX_PER_ROUTE);
closeableHttpClient = initializeClient();
// 启动监控线程,监控空闲链接并回收资源
monitorTask();
}
private void monitorTask(){
monitorExecutor = new ScheduledThreadPoolExecutor(1);
monitorExecutor.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
//关闭异常连接
connectionManager.closeExpiredConnections();
//关闭5s空闲的连接
connectionManager.closeIdleConnections(5000, TimeUnit.MILLISECONDS);
}
}, 5000, 5000, TimeUnit.MILLISECONDS);
}
private RequestConfig initRequestConfig(HttpRequestBase httpRequest) {
Header[] cookies = httpRequest.getHeaders("Cookie");
RequestConfig.Builder builder = RequestConfig.custom();
builder.setSocketTimeout(SOCKET_TIME_OUT )
.setConnectTimeout(CONNECT_TIME_OUT)
.setConnectionRequestTimeout(REQUEST_TIME_OUT);
if (cookies != null && cookies.length > 0) {
builder.setCookieSpec(CookieSpecs.STANDARD);
}
else {
builder.setCookieSpec(CookieSpecs.IGNORE_COOKIES);
}
return builder.build();
}
public CloseableHttpClient createClient(){
return closeableHttpClient;
}
private CloseableHttpClient initializeClient(){
return HttpClients.custom()
.setConnectionManager(connectionManager)
.setRedirectStrategy(new LaxRedirectStrategy())
.build();
}
public void setRequestConfig(HttpRequestBase httpRequest){
httpRequest.setConfig(initRequestConfig(httpRequest));
}
}