您的位置 首页 java

Java,HttpClient4.5,https及使用连接池

技术环境:

idea2019 + maven3.6 + java8 + httpclient4.5

连接池参数说明:

maxTotal,最大连接数===>连接池里的最大连接数;

connectTimeout,连接超时==>指客户端和服务器建立连接的timeout;

socketTimeout,读超时===>客户端和服务器建立连接后,客户端从服务器读取数据的timeout,超出后会抛出SocketTimeOutException;

connectionRequestTimeout,请求超时==>指从连接池获取连接的timeout;

defaultMaxPerRoute、maxPerRoute,每次能并行接收的请求数量===>某一个/每服务每次能并行接收的请求数量,这里route指的是域名;

retryCount,重试次数;

requestSentRetryEnabled,请求失败是否重发;

evictIdleConnections,移除空闲连接时间;

共享代码:

pom.xml

 <dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpclient</artifactId>
    <version>4.5.13</version>
</dependency>
<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpmime</artifactId>
    <version>4.5.13</version>
</dependency>
<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpasyncclient</artifactId>
    <version>4.1</version>
</dependency>  

HttpConnectionPoolManager(连接池类):

 import org.apache.http.HttpHost;
import org.apache.http.client.HttpRequestRetryHandler;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.HttpClientConnectionManager;
import org.apache.http.conn.routing.HttpRoute;
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.springframework.util.StringUtils;

import javax.net.ssl.SSLContext;
import java.util.Properties;
import java.util.concurrent.TimeUnit;

public final class HttpConnectionPoolManager {

    private Properties props;
    private String hostname;
    private int port;
    private PoolingHttpClientConnectionManager httpClientConnectionManager;
    private IdleConnectionEvictor idleConnectionEvictor;

    /**
     * @param hostname
     * @param port
     */    public HttpConnectionPoolManager(String hostname, int port) {
        this.hostname = hostname;
        this.port = port;
        props = new Properties();
        //==================================================================================================//
        // 最大连接数===>连接池里的最大连接数
        //==================================================================================================//
        props.setProperty("maxTotal", String.valueOf(20));
        //==================================================================================================//
        // 连接超时==>指客户端和服务器建立连接的timeout
        //==================================================================================================//
        props.setProperty("connectTimeout", String.valueOf(60 * 1000));
        //==================================================================================================//
        // 读超时===>客户端和服务器建立连接后,客户端从服务器读取数据的timeout,超出后会抛出SocketTimeOutException
        //==================================================================================================//
        props.setProperty("socketTimeout", String.valueOf(30 * 1000));
        //==================================================================================================//
        // 请求超时==>指从连接池获取连接的timeout
        //==================================================================================================//
        props.setProperty("connectionRequestTimeout", String.valueOf(10 * 1000));
        //==================================================================================================//
        // 每次能并行接收的请求数量===>某一个/每服务每次能并行接收的请求数量,这里route指的是域名
        //==================================================================================================//
        props.setProperty("defaultMaxPerRoute", String.valueOf(40));
        props.setProperty("maxPerRoute", String.valueOf(60));
        //==================================================================================================//
        // 重试次数、请求失败是否重发
        //==================================================================================================//
        props.setProperty("retryCount", String.valueOf(3));
        props.setProperty("requestSentRetryEnabled", String.valueOf(false));
        //==================================================================================================//
        // 移除空闲连接时间
        //==================================================================================================//
        props.setProperty("evictIdleConnections", String.valueOf(30 * 10000));
    }

    /**
     * @param props
     * @param hostname
     * @param port
     */    public HttpConnectionPoolManager(Properties props, String hostname, int port) {
        this.props = props;
        this.hostname = hostname;
        this.port = port;
    }

    /**
     * @return
     */    private PoolingHttpClientConnectionManager getConnectionManager() {
        if (httpClientConnectionManager == null) {
            synchronized (this) {
                if (httpClientConnectionManager == null) {
                    httpClientConnectionManager = createConnectionManager();
                }
            }
        }
        return httpClientConnectionManager;
    }

    /**
     * @return
     */    private Registry<ConnectionSocketFactory> createSocketFactoryRegistry() {
        SSLContext sslContext = MySSLContextUtils.createDefaultSSLContext();
        Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder
                .<ConnectionSocketFactory>create()
                .register("http", PlainConnectionSocketFactory.INSTANCE)
                .register("https", new SSLConnectionSocketFactory(sslContext))
                .build();
        return socketFactoryRegistry;
    }

    /**
     * @return
     */    private PoolingHttpClientConnectionManager createConnectionManager() {
        PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(createSocketFactoryRegistry());
        connectionManager.setMaxTotal(getIntProperty("maxTotal", 20));
        connectionManager.setDefaultMaxPerRoute(getIntProperty("defaultMaxPerRoute", 40));
        HttpHost httpHost = new HttpHost(hostname, port);
        HttpRoute httpRoute = new HttpRoute(httpHost);
        connectionManager.setMaxPerRoute(httpRoute, getIntProperty("maxPerRoute", 40));
        // 清理无效连接
        idleConnectionEvictor = new IdleConnectionEvictor(connectionManager);
        idleConnectionEvictor.setName("httpclient-connection-" + httpHost.toString() + "-idle-thread");
        idleConnectionEvictor.setDaemon(true);
        idleConnectionEvictor.start();
        return connectionManager;
    }

    /**
     * @return
     */    public CloseableHttpClient getDefaultCustomClient() {
        int connectTimeoutMillisecond = getIntProperty("connectTimeout", 60 * 1000);
        int socketTimeoutMillisecond = getIntProperty("socketTimeout", 30 * 1000);
        int connectionRequestTimeoutMillisecond = getIntProperty("connectionRequestTimeout", 10 * 1000);
        int retryCount = getIntProperty("retryCount", 3);
        boolean requestSentRetryEnabled = getBoolProperty("requestSentRetryEnabled", false);
        int evictIdleConnectionsMillisecond = getIntProperty("evictIdleConnections", 30 * 10000);
        return getCustomClient(connectTimeoutMillisecond, socketTimeoutMillisecond, connectionRequestTimeoutMillisecond, retryCount, requestSentRetryEnabled, evictIdleConnectionsMillisecond);
    }

    /**
     * @param name
     * @param defaultValue
     * @return
     */    private int getIntProperty(String name, int defaultValue) {
        String value = props.getProperty(name, String.valueOf(defaultValue));
        if (!StringUtils.isEmpty(value)) {
            return Integer.parseInt(value);
        }
        return defaultValue;
    }

    /**
     * @param name
     * @param defaultValue
     * @return
     */    private boolean getBoolProperty(String name, boolean defaultValue) {
        String value = props.getProperty(name, String.valueOf(defaultValue));
        if (!StringUtils.isEmpty(value)) {
            return Boolean.parseBoolean(value);
        }
        return defaultValue;
    }

    /**
     * @param connectTimeoutMillisecond
     * @param socketTimeoutMillisecond
     * @param connectionRequestTimeoutMillisecond
     * @param retryCount
     * @param requestSentRetryEnabled
     * @param evictIdleConnectionsMillisecond
     * @return
     */    public CloseableHttpClient getCustomClient(int connectTimeoutMillisecond, int socketTimeoutMillisecond, int connectionRequestTimeoutMillisecond,
                                               int retryCount, boolean requestSentRetryEnabled, int evictIdleConnectionsMillisecond) {
        //默认连接配置
        RequestConfig defaultRequestConfig = RequestConfig.custom()
                .setConnectTimeout(connectTimeoutMillisecond)
                .setSocketTimeout(socketTimeoutMillisecond)
                .setConnectionRequestTimeout(connectionRequestTimeoutMillisecond)
                .build();
        //  retryCount==>重试次数, requestSentRetryEnabled==>允许请求重发
        HttpRequestRetryHandler httpRetryHandler = new DefaultHttpRequestRetryHandler(retryCount, requestSentRetryEnabled);
        return HttpClients.custom()
                .setDefaultRequestConfig(defaultRequestConfig)
                .evictExpiredConnections()
                .setConnectionManagerShared(false)
                .evictIdleConnections(evictIdleConnectionsMillisecond, TimeUnit.MILLISECONDS)
                .setConnectionManager(getConnectionManager())
                .setRetryHandler(httpRetryHandler).build();
    }


    /**
     * 监听连接池中空闲连接,清理无效连接
     */    class IdleConnectionEvictor extends Thread {

        private final HttpClientConnectionManager connectionManager;

        private volatile boolean shutdown;

        public IdleConnectionEvictor(HttpClientConnectionManager connectionManager) {
            this.connectionManager = connectionManager;
        }

        @Override
        public void run() {
            try {
                while (!shutdown) {
                    synchronized (this) {
                        //3s检查一次
                        this.wait(3000);
                        // 关闭失效的连接
                        connectionManager.closeExpiredConnections();
                    }
                }
            } catch (InterruptedException ex) {
                ex.printStackTrace();
            }
        }

        public void shutdown() {
            shutdown = true;
            synchronized (this) {
                notifyAll();
            }
        }
    }

    /**
     * 关闭连接池
     */    public void shutdownConnectionManager() {
        if (idleConnectionEvictor != null) {
            idleConnectionEvictor.shutdown();
            idleConnectionEvictor = null;
        }
        if (httpClientConnectionManager != null) {
            httpClientConnectionManager.shutdown();
            httpClientConnectionManager = null;
        }
    }

}  

SSLContext工具类:

 import org.apache.http.conn.ssl.TrustSelfSignedStrategy;
import org.apache.http.ssl.SSLContexts;

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.NoSuchAlgorithmException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

public final class MySSLContextUtils {

    /**
     * @return
     */    public static SSLContext createDefaultSSLContext() {
        if (false) {
            // 单向认证,随意的证书与服务端可信交互,连接建立后,协商使用对称加密算法通信
            return createGenerateSSLContext();
        } else if (false) {
            // 单向认证,随意的证书与服务端可信交互,连接建立后,协商使用对称加密算法通信
            return createKeystoreSSLContext();
        } else {
            // 双向认证,服务端验证客户端证书(从证书可中获取传递),客户端验证服务端证书(代码中验证)
            return createKeystoreAliasSSLContext();
        }
    }

    /**
     * @return
     */    private static SSLContext createGenerateSSLContext() {
        SSLContext sslContext = null;
        try {
            sslContext = SSLContext.getInstance("SSL");
            TrustManager[] trustAllCerts = new TrustManager[]{new X509TrustManager() {
                @Override
                public void checkClientTrusted(java.security.cert.X509Certificate[] x509Certificates, String s) throws CertificateException {
                }

                @Override
                public void checkServerTrusted(java.security.cert.X509Certificate[] x509Certificates, String s) throws CertificateException {
                }

                @Override
                public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                    return null;
                }
            }};
            sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
        } catch (KeyManagementException e) {
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        return sslContext;
    }

    /**
     * @return
     */    public static SSLContext createKeystoreSSLContext() {
        File keystoreFile = new File("D:\\client.jks");
        String keystorePassword = "123456";
        return createSSLContext(keystoreFile, keystorePassword);
    }

    /**
     * keytool -genkey -dname "CN=XFDClient,OU=XFDUnit,O=XFD,L=TaiYuan, ST=ShanXi, C=CN" -keysize 2048 -alias client -keyalg RSA -keystore d:/client.jks -keypass 123456 -storepass 123456 -validity 36500
     *
     * @param keystoreFile
     * @param keystorePassword
     * @return
     */    public static SSLContext createSSLContext(File keystoreFile, String keystorePassword) {
        SSLContext sslcontext = null;
        try {
            // 设置truststore
            KeyStore trustStore = KeyStore.getInstance("JKS");
            InputStream keystoreInput = new FileInputStream(keystoreFile);
            try {
                trustStore.load(keystoreInput, keystorePassword.toCharArray());
            } finally {
                try {
                    keystoreInput.close();
                } catch (Exception ignore) {
                }
            }
            sslcontext = SSLContexts.custom().loadTrustMaterial(trustStore, new TrustSelfSignedStrategy()).build();
            // 创建TrustManager(空的)
            X509TrustManager trustManager = new X509TrustManager() {

                public void checkClientTrusted(X509Certificate[] chain, String authenType) throws CertificateException {
                    // 检查客户端证书
                }

                public void checkServerTrusted(X509Certificate[] chain, String authenType) throws CertificateException {
                    // 检查服务器端证书
                }

                public X509Certificate[] getAcceptedIssuers() {
                    // 返回受信任的X509证书数组
                    return new java.security.cert.X509Certificate[0];
                }
            };
            sslcontext.init(null, new TrustManager[]{trustManager}, null);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return sslcontext;
    }

    /**
     * @return
     */    public static SSLContext createKeystoreAliasSSLContext() {
        File keystoreFile = new File("D:\\client.jks");
        String keystorePassword = "123456";
        String alias = "client";
        return createSSLContext(keystoreFile, keystorePassword, alias);
    }

    /**
     * keytool -genkey -dname "CN=XFDClient,OU=XFDUnit,O=XFD,L=TaiYuan, ST=ShanXi, C=CN" -keysize 2048 -alias client -keyalg RSA -keystore d:/client.jks -keypass 123456 -storepass 123456 -validity 36500
     *
     * @param keystoreFile
     * @param keystorePassword
     * @return
     */    public static SSLContext createSSLContext(File keystoreFile, String keystorePassword, String alias) {
        SSLContext sslcontext = null;
        try {
            // 设置truststore
            KeyStore trustStore = KeyStore.getInstance("JKS");
            InputStream keystoreInput = new FileInputStream(keystoreFile);
            try {
                trustStore.load(keystoreInput, keystorePassword.toCharArray());
            } finally {
                try {
                    keystoreInput.close();
                } catch (Exception ignore) {
                }
            }
            sslcontext = SSLContexts.custom().loadTrustMaterial(trustStore, new TrustSelfSignedStrategy()).build();
            // 从证书库中根据alias获取证书链
            Certificate[] certificates = trustStore.getCertificateChain(alias);
            // 转换成X509Certificate
            X509Certificate[] x509Certificates = new X509Certificate[certificates.length];
            for (int i = 0; i < certificates.length; i++) {
                x509Certificates[i] = (X509Certificate) certificates[i];
            }
            // 创建TrustManager(空的)
            X509TrustManager trustManager = new X509TrustManager() {

                public void checkClientTrusted(X509Certificate[] chain, String authenType) throws CertificateException {
                    // 检查客户端证书
                    System.out.println("客户端证书 = " + authenType);
                }

                public void checkServerTrusted(X509Certificate[] chain, String authenType) throws CertificateException {
                    // 检查服务器端证书
                    System.out.println("服务器端证书 = " + authenType);
                }

                public X509Certificate[] getAcceptedIssuers() {
                    // 返回受信任的X509证书数组
                    return x509Certificates;
                }
            };
            sslcontext.init(null, new TrustManager[]{trustManager}, null);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return sslcontext;
    }

}  

证书生成,参考地址:

1、

2、

测试类:

 import com.alibaba.fastjson.JSON;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

public class HttpConnectionPoolManagerDemo {

    public static void main(String[] args) {
        String host = "www.sxmfyy.com";
        int port = 443;
        HttpConnectionPoolManager poolManager = new HttpConnectionPoolManager(host, port);
        // 调用URL
        String url = "#34;;
        // 请求参数
        Map<String,Object> requestJsonMap = new HashMap<>();
        requestJsonMap.put("username","admin");
        requestJsonMap.put("password","xxxxxx");
        String requestJson = JSON.toJSONString(requestJsonMap);
        //
        CloseableHttpClient httpClient = poolManager.getDefaultCustomClient();
        HttpPost httpPost = new HttpPost(url);
        // httpPost.addHeader("Authorization", "");
        StringEntity requestEntity = new StringEntity(requestJson, "UTF-8");
        requestEntity.setContentType("application/json");
        httpPost.setEntity(requestEntity);
        CloseableHttpResponse response = null;
        String responseJson = "";
        try {
            response = httpClient.execute(httpPost);
            HttpEntity responseEntity = response.getEntity();
            System.out.println("statusLine=>" + response.getStatusLine());
            responseJson = EntityUtils.toString(responseEntity, "UTF-8");
        } catch (IOException e) {
            e.printStackTrace();
        }
        System.out.println("responseJson=>" + responseJson);
        // 关闭
        poolManager.shutdownConnectionManager();
    }

}  

文章来源:智云一二三科技

文章标题:Java,HttpClient4.5,https及使用连接池

文章地址:https://www.zhihuclub.com/183809.shtml

关于作者: 智云科技

热门文章

网站地图