异步httpclient---HttpAsyncClient的使用

来源:互联网 发布:js 数字比大小 编辑:程序博客网 时间:2024/05/18 12:04

这两天研究了一下异步的httpclient ---- httpAsyncClient

原来使用httpclient都是同步的,如果项目中有大量的httpclient的话,可能会造成阻塞,如果使用异步请求的话可以避免这些问题

可以用在调用第三方接口或者不需要知道请求返回结果的场景下

于是写了一个工具类来封装了同步异步httpclient


github地址:https://github.com/a63881763/HttpAsyncClientUtils



1.首先需要在pom中添加需要的jar

<properties>        <!-- log4j日志包版本号 -->        <slf4j.version>1.7.25</slf4j.version>        <log4j.version>2.8.2</log4j.version>    </properties>    <dependencies>        <dependency>            <groupId>org.apache.httpcomponents</groupId>            <artifactId>httpclient</artifactId>            <version>4.5.1</version>        </dependency>        <dependency>            <groupId>org.apache.httpcomponents</groupId>            <artifactId>httpcore</artifactId>            <version>4.4.6</version>        </dependency>        <dependency>            <groupId>org.apache.httpcomponents</groupId>            <artifactId>httpmime</artifactId>            <version>4.3.1</version>        </dependency>        <dependency>            <groupId>org.apache.httpcomponents</groupId>            <artifactId>httpasyncclient</artifactId>            <version>4.1.3</version>        </dependency>        <dependency>            <groupId>commons-lang</groupId>            <artifactId>commons-lang</artifactId>            <version>2.6</version>        </dependency>        <!-- https://mvnrepository.com/artifact/org.slf4j/jcl-over-slf4j -->        <!--用log4j接管commons-logging-->        <!-- log配置:Log4j2 + Slf4j -->        <dependency>            <groupId>org.apache.logging.log4j</groupId>            <artifactId>log4j-api</artifactId>            <version>${log4j.version}</version>        </dependency>        <dependency>            <groupId>org.apache.logging.log4j</groupId>            <artifactId>log4j-core</artifactId>            <version>${log4j.version}</version>        </dependency>        <dependency> <!-- 桥接:告诉Slf4j使用Log4j2 -->            <groupId>org.apache.logging.log4j</groupId>            <artifactId>log4j-slf4j-impl</artifactId>            <version>${log4j.version}</version>        </dependency>        <dependency> <!-- 桥接:告诉commons logging使用Log4j2 -->            <groupId>org.apache.logging.log4j</groupId>            <artifactId>log4j-jcl</artifactId>            <version>${log4j.version}</version>        </dependency>        <dependency>            <groupId>org.slf4j</groupId>            <artifactId>slf4j-api</artifactId>            <version>${slf4j.version}</version>        </dependency>        <dependency>            <groupId>com.alibaba</groupId>            <artifactId>fastjson</artifactId>            <version>1.2.39</version>        </dependency>    </dependencies>


2.HttpAsyncClient的连接池类

import org.apache.http.Consts;import org.apache.http.HttpHost;import org.apache.http.auth.AuthSchemeProvider;import org.apache.http.auth.AuthScope;import org.apache.http.auth.MalformedChallengeException;import org.apache.http.auth.UsernamePasswordCredentials;import org.apache.http.client.CredentialsProvider;import org.apache.http.client.config.AuthSchemes;import org.apache.http.client.config.RequestConfig;import org.apache.http.config.ConnectionConfig;import org.apache.http.config.Lookup;import org.apache.http.config.Registry;import org.apache.http.config.RegistryBuilder;import org.apache.http.conn.ssl.SSLContexts;import org.apache.http.impl.auth.*;import org.apache.http.impl.client.BasicCookieStore;import org.apache.http.impl.client.BasicCredentialsProvider;import org.apache.http.impl.nio.client.CloseableHttpAsyncClient;import org.apache.http.impl.nio.client.HttpAsyncClients;import org.apache.http.impl.nio.conn.PoolingNHttpClientConnectionManager;import org.apache.http.impl.nio.reactor.DefaultConnectingIOReactor;import org.apache.http.impl.nio.reactor.IOReactorConfig;import org.apache.http.nio.conn.NoopIOSessionStrategy;import org.apache.http.nio.conn.SchemeIOSessionStrategy;import org.apache.http.nio.conn.ssl.SSLIOSessionStrategy;import org.apache.http.nio.reactor.ConnectingIOReactor;import org.apache.http.nio.reactor.IOReactorException;import javax.net.ssl.SSLContext;import java.nio.charset.CodingErrorAction;import java.security.KeyManagementException;import java.security.KeyStoreException;import java.security.NoSuchAlgorithmException;import java.security.UnrecoverableKeyException;/** * 异步的HTTP请求对象,可设置代理 */public class HttpAsyncClient {    private static int socketTimeout = 1000;// 设置等待数据超时时间5秒钟 根据业务调整    private static int connectTimeout = 2000;// 连接超时    private static int poolSize = 3000;// 连接池最大连接数    private static int maxPerRoute = 1500;// 每个主机的并发最多只有1500    // http代理相关参数    private String host = "";    private int port = 0;    private String username = "";    private String password = "";    // 异步httpclient    private CloseableHttpAsyncClient asyncHttpClient;    // 异步加代理的httpclient    private CloseableHttpAsyncClient proxyAsyncHttpClient;    public HttpAsyncClient() {        try {            this.asyncHttpClient = createAsyncClient(false);            this.proxyAsyncHttpClient = createAsyncClient(true);        } catch (Exception e) {            e.printStackTrace();        }    }    public CloseableHttpAsyncClient createAsyncClient(boolean proxy)            throws KeyManagementException, UnrecoverableKeyException,            NoSuchAlgorithmException, KeyStoreException,            MalformedChallengeException, IOReactorException {        RequestConfig requestConfig = RequestConfig.custom()                .setConnectTimeout(connectTimeout)                .setSocketTimeout(socketTimeout).build();        SSLContext sslcontext = SSLContexts.createDefault();        UsernamePasswordCredentials credentials = new UsernamePasswordCredentials(                username, password);        CredentialsProvider credentialsProvider = new BasicCredentialsProvider();        credentialsProvider.setCredentials(AuthScope.ANY, credentials);        // 设置协议http和https对应的处理socket链接工厂的对象        Registry<SchemeIOSessionStrategy> sessionStrategyRegistry = RegistryBuilder                .<SchemeIOSessionStrategy> create()                .register("http", NoopIOSessionStrategy.INSTANCE)                .register("https", new SSLIOSessionStrategy(sslcontext))                .build();        // 配置io线程        IOReactorConfig ioReactorConfig = IOReactorConfig.custom()                .setIoThreadCount(Runtime.getRuntime().availableProcessors())                .build();        // 设置连接池大小        ConnectingIOReactor ioReactor;        ioReactor = new DefaultConnectingIOReactor(ioReactorConfig);        PoolingNHttpClientConnectionManager conMgr = new PoolingNHttpClientConnectionManager(                ioReactor, null, sessionStrategyRegistry, null);        if (poolSize > 0) {            conMgr.setMaxTotal(poolSize);        }        if (maxPerRoute > 0) {            conMgr.setDefaultMaxPerRoute(maxPerRoute);        } else {            conMgr.setDefaultMaxPerRoute(10);        }        ConnectionConfig connectionConfig = ConnectionConfig.custom()                .setMalformedInputAction(CodingErrorAction.IGNORE)                .setUnmappableInputAction(CodingErrorAction.IGNORE)                .setCharset(Consts.UTF_8).build();        Lookup<AuthSchemeProvider> authSchemeRegistry = RegistryBuilder                .<AuthSchemeProvider> create()                .register(AuthSchemes.BASIC, new BasicSchemeFactory())                .register(AuthSchemes.DIGEST, new DigestSchemeFactory())                .register(AuthSchemes.NTLM, new NTLMSchemeFactory())                .register(AuthSchemes.SPNEGO, new SPNegoSchemeFactory())                .register(AuthSchemes.KERBEROS, new KerberosSchemeFactory())                .build();        conMgr.setDefaultConnectionConfig(connectionConfig);        if (proxy) {            return HttpAsyncClients.custom().setConnectionManager(conMgr)                    .setDefaultCredentialsProvider(credentialsProvider)                    .setDefaultAuthSchemeRegistry(authSchemeRegistry)                    .setProxy(new HttpHost(host, port))                    .setDefaultCookieStore(new BasicCookieStore())                    .setDefaultRequestConfig(requestConfig).build();        } else {            return HttpAsyncClients.custom().setConnectionManager(conMgr)                    .setDefaultCredentialsProvider(credentialsProvider)                    .setDefaultAuthSchemeRegistry(authSchemeRegistry)                    .setDefaultCookieStore(new BasicCookieStore()).build();        }    }    public CloseableHttpAsyncClient getAsyncHttpClient() {        return asyncHttpClient;    }    public CloseableHttpAsyncClient getProxyAsyncHttpClient() {        return proxyAsyncHttpClient;    }}

3.httpclient的工厂类


/** * * httpclient 工厂类 * */public class HttpClientFactory {    private static HttpAsyncClient httpAsyncClient = new HttpAsyncClient();    private static HttpSyncClient httpSyncClient = new HttpSyncClient();    private HttpClientFactory() {    }    private static HttpClientFactory httpClientFactory = new HttpClientFactory();    public static HttpClientFactory getInstance() {        return httpClientFactory;    }    public HttpAsyncClient getHttpAsyncClientPool() {        return httpAsyncClient;    }    public HttpSyncClient getHttpSyncClientPool() {        return httpSyncClient;    }}


4.httpclient的util

2017.11.22

发现每次异步连接回调成功后,连接总是延迟很久关,查了不少资料,发现httpAsyncClient默认是长连接,所以在不需要长连接的时候记得要把请求头中的connection设成false





/** * * http client 业务逻辑处理类 * */public class HttpClientUtil {    private static Logger LOG = LoggerFactory            .getLogger(HttpClientUtil.class);    private static String utf8Charset = "utf-8";    /**     * 向指定的url发送一次post请求,参数是List<NameValuePair>     * @param baseUrl 请求地址     * @param list 请求参数,格式是List<NameValuePair>     * @return 返回结果,请求失败时返回null     * @apiNote http接口处用 @RequestParam接收参数     */    public static String httpSyncPost(String baseUrl,List<BasicNameValuePair> list) {        CloseableHttpClient httpClient = HttpClientFactory.getInstance().getHttpSyncClientPool().getHttpClient();        HttpPost httpPost = new HttpPost(baseUrl);        //Parameters        LOG.warn("==== Parameters ======" +list);        CloseableHttpResponse response  = null;        try {            httpPost.setEntity(new UrlEncodedFormEntity(list));            response = httpClient.execute(httpPost);            LOG.warn("========HttpResponseProxy:========"+response.getStatusLine());            HttpEntity entity = response.getEntity();            String result = null;            if(entity != null){                result = EntityUtils.toString(entity, "UTF-8");                LOG.warn("========Response=======" +result);            }            EntityUtils.consume(entity);            return result;        } catch (Exception e) {            e.printStackTrace();        }finally {            if(response != null){                try {                    response.close();                } catch (IOException e) {                    e.printStackTrace();                }            }        }        return null;    }    /**     * 向指定的url发送一次post请求,参数是字符串     * @param baseUrl 请求地址     * @param postString 请求参数,格式是json.toString()     * @return 返回结果,请求失败时返回null     * @apiNote http接口处用 @RequestBody接收参数     */    public static String httpSyncPost(String baseUrl, String postString)  {        CloseableHttpClient httpClient = HttpClientFactory.getInstance().getHttpSyncClientPool().getHttpClient();        HttpPost httpPost = new HttpPost(baseUrl);        //parameters        LOG.warn("==== Parameters ======" +postString);        CloseableHttpResponse response  = null;        try {            if(postString == null || "".equals(postString)){                throw new Exception("missing post String");            }            StringEntity stringEntity = new StringEntity(postString.toString(), utf8Charset);            stringEntity.setContentEncoding("UTF-8");            stringEntity.setContentType("application/json");            httpPost.setEntity(stringEntity);            response = httpClient.execute(httpPost);            LOG.warn("========HttpResponseProxy:========"+response.getStatusLine());            HttpEntity entity = response.getEntity();            String result = null;            if(entity != null){                result = EntityUtils.toString(entity, "UTF-8");                LOG.warn("========Response=======" +result);            }            EntityUtils.consume(entity);            return result;        } catch (Exception e) {            e.printStackTrace();        }finally {            if(response != null){                try {                    response.close();                } catch (IOException e) {                    e.printStackTrace();                }            }        }        return null;    }    /**     * 向指定的url发送一次get请求,参数是List<NameValuePair>     * @param baseUrl 请求地址     * @param list 请求参数,格式是List<NameValuePair>     * @return 返回结果,请求失败时返回null     * @apiNote http接口处用 @RequestParam接收参数     */    public static String httpSyncGet(String baseUrl, List<BasicNameValuePair> list)  {        CloseableHttpClient httpClient = HttpClientFactory.getInstance().getHttpSyncClientPool().getHttpClient();        HttpGet httpGet = new HttpGet(baseUrl);        //Parameters        LOG.warn("==== Parameters ======" +list);        CloseableHttpResponse response  = null;        try {            if(list != null){                String getUrl = EntityUtils                        .toString(new UrlEncodedFormEntity(list));                httpGet.setURI(new URI(httpGet.getURI().toString()                        + "?" + getUrl));            }            else{                httpGet.setURI(new URI(httpGet.getURI().toString()));            }            response = httpClient.execute(httpGet);            LOG.warn("========HttpResponseProxy:========"+response.getStatusLine());            HttpEntity entity = response.getEntity();            String result = null;            if(entity != null){                result = EntityUtils.toString(entity, "UTF-8");                LOG.warn("========Response=======" +result);            }            EntityUtils.consume(entity);            return result;        } catch (Exception e) {            e.printStackTrace();        }finally {            if(response != null){                try {                    response.close();                } catch (IOException e) {                    e.printStackTrace();                }            }        }        return null;    }    /**     * 向指定的url发送一次get请求,参数是字符串     * @param baseUrl 请求地址     * @param urlParams 请求参数,格式是String     * @return 返回结果,请求失败时返回null     * @apiNote http接口处用 @RequestParam接收参数     */    public static String httpSyncGet(String baseUrl,String urlParams)  {        CloseableHttpClient httpClient = HttpClientFactory.getInstance().getHttpSyncClientPool().getHttpClient();        HttpGet httpGet = new HttpGet(baseUrl);        //Parameters        LOG.warn("==== Parameters ======" +urlParams);        CloseableHttpResponse response  = null;        try {            if (null != urlParams || "".equals(urlParams)) {                httpGet.setURI(new URI(httpGet.getURI().toString()                        + "?" + urlParams));            }            else{                httpGet.setURI(new URI(httpGet.getURI().toString()));            }            response = httpClient.execute(httpGet);            LOG.warn("========HttpResponseProxy:========"+response.getStatusLine());            HttpEntity entity = response.getEntity();            String result = null;            if(entity != null){                result = EntityUtils.toString(entity, "UTF-8");                LOG.warn("========Response=======" +result);            }            EntityUtils.consume(entity);            return result;        } catch (Exception e) {            e.printStackTrace();        }finally {            if(response != null){                try {                    response.close();                } catch (IOException e) {                    e.printStackTrace();                }            }        }        return null;    }    /**     * 向指定的url发送一次get请求,参数是字符串     * @param baseUrl 请求地址     * @return 返回结果,请求失败时返回null     * @apiNote http接口处用 @RequestParam接收参数     */    public static String httpSyncGet(String baseUrl)  {        CloseableHttpClient httpClient = HttpClientFactory.getInstance().getHttpSyncClientPool().getHttpClient();        HttpGet httpGet = new HttpGet(baseUrl);        CloseableHttpResponse response  = null;        try {            httpGet.setURI(new URI(httpGet.getURI().toString()));            response = httpClient.execute(httpGet);            LOG.warn("========HttpResponseProxy:========"+response.getStatusLine());            HttpEntity entity = response.getEntity();            String result = null;            if(entity != null){                result = EntityUtils.toString(entity, "UTF-8");                LOG.warn("========Response=======" +result);            }            EntityUtils.consume(entity);            return result;        } catch (Exception e) {            e.printStackTrace();        }finally {            if(response != null){                try {                    response.close();                } catch (IOException e) {                    e.printStackTrace();                }            }        }        return null;    }    /**     * 向指定的url发送一次异步post请求,参数是字符串     * @param baseUrl 请求地址     * @param postString 请求参数,格式是json.toString()     * @param urlParams 请求参数,格式是String     * @param callback 回调方法,格式是FutureCallback     * @return 返回结果,请求失败时返回null     * @apiNote http接口处用 @RequestParam接收参数     */    public static void httpAsyncPost(String baseUrl,String postString,                              String urlParams,FutureCallback callback) throws Exception {        if (baseUrl == null || "".equals(baseUrl)) {            LOG.warn("we don't have base url, check config");            throw new Exception("missing base url");        }        CloseableHttpAsyncClient hc = HttpClientFactory.getInstance().getHttpAsyncClientPool()                .getAsyncHttpClient();        try {            hc.start();            HttpPost httpPost = new HttpPost(baseUrl);            httpPost.setHeader("Connection","close");            if (null != postString) {                LOG.debug("exeAsyncReq post postBody={}", postString);                StringEntity entity = new StringEntity(postString.toString(), utf8Charset);                entity.setContentEncoding("UTF-8");                entity.setContentType("application/json");                httpPost.setEntity(entity);            }            if (null != urlParams) {                httpPost.setURI(new URI(httpPost.getURI().toString()                        + "?" + urlParams));            }            LOG.warn("exeAsyncReq getparams:" + httpPost.getURI());            hc.execute(httpPost, callback);        } catch (Exception e) {            e.printStackTrace();        }    }    /**     * 向指定的url发送一次异步post请求,参数是字符串     * @param baseUrl 请求地址     * @param urlParams 请求参数,格式是List<BasicNameValuePair>     * @param callback 回调方法,格式是FutureCallback     * @return 返回结果,请求失败时返回null     * @apiNote http接口处用 @RequestParam接收参数     */    public static void httpAsyncPost(String baseUrl, List<BasicNameValuePair> postBody,                              List<BasicNameValuePair> urlParams, FutureCallback callback ) throws Exception {        if (baseUrl == null || "".equals(baseUrl)) {            LOG.warn("we don't have base url, check config");            throw new Exception("missing base url");        }        try {            CloseableHttpAsyncClient hc = HttpClientFactory.getInstance().getHttpAsyncClientPool()                    .getAsyncHttpClient();            hc.start();            HttpPost httpPost = new HttpPost(baseUrl);            httpPost.setHeader("Connection","close");            if (null != postBody) {                LOG.debug("exeAsyncReq post postBody={}", postBody);                UrlEncodedFormEntity entity = new UrlEncodedFormEntity(                        postBody, "UTF-8");                httpPost.setEntity(entity);            }            if (null != urlParams) {                String getUrl = EntityUtils                        .toString(new UrlEncodedFormEntity(urlParams));                httpPost.setURI(new URI(httpPost.getURI().toString()                        + "?" + getUrl));            }            LOG.warn("exeAsyncReq getparams:" + httpPost.getURI());            hc.execute(httpPost, callback);        } catch (Exception e) {            e.printStackTrace();        }    }    /**     * 向指定的url发送一次异步get请求,参数是String     * @param baseUrl 请求地址     * @param urlParams 请求参数,格式是String     * @param callback 回调方法,格式是FutureCallback     * @return 返回结果,请求失败时返回null     * @apiNote http接口处用 @RequestParam接收参数     */    public static void httpAsyncGet(String baseUrl,String urlParams,FutureCallback callback) throws Exception {        if (baseUrl == null || "".equals(baseUrl)) {            LOG.warn("we don't have base url, check config");            throw new Exception("missing base url");        }        CloseableHttpAsyncClient hc = HttpClientFactory.getInstance().getHttpAsyncClientPool()                .getAsyncHttpClient();        try {            hc.start();            HttpGet httpGet = new HttpGet(baseUrl);            httpGet.setHeader("Connection","close");            if (null != urlParams || "".equals(urlParams)) {                httpGet.setURI(new URI(httpGet.getURI().toString()                        + "?" + urlParams));            }            else{                httpGet.setURI(new URI(httpGet.getURI().toString()));            }            LOG.warn("exeAsyncReq getparams:" + httpGet.getURI());            hc.execute(httpGet,  callback);        } catch (Exception e) {            e.printStackTrace();        }    }    /**     * 向指定的url发送一次异步get请求,参数是List<BasicNameValuePair>     * @param baseUrl 请求地址     * @param urlParams 请求参数,格式是List<BasicNameValuePair>     * @param callback 回调方法,格式是FutureCallback     * @return 返回结果,请求失败时返回null     * @apiNote http接口处用 @RequestParam接收参数     */    public static void httpAsyncGet(String baseUrl, List<BasicNameValuePair> urlParams, FutureCallback callback) throws Exception {        if (baseUrl == null || "".equals(baseUrl)) {            LOG.warn("we don't have base url, check config");            throw new Exception("missing base url");        }        try {            CloseableHttpAsyncClient hc = HttpClientFactory.getInstance().getHttpAsyncClientPool()                    .getAsyncHttpClient();            hc.start();            HttpPost httpGet = new HttpPost(baseUrl);            httpGet.setHeader("Connection","close");            if (null != urlParams) {                String getUrl = EntityUtils                        .toString(new UrlEncodedFormEntity(urlParams));                httpGet.setURI(new URI(httpGet.getURI().toString()                        + "?" + getUrl));            }            LOG.warn("exeAsyncReq getparams:" + httpGet.getURI());            hc.execute(httpGet, callback);        } catch (Exception e) {            e.printStackTrace();        }    }}







工具类种有8种同步异步的post和get请求,通过不同的参数获得结果



本文章参考了http://blog.csdn.net/angjunqiang/article/details/55259170

 
阅读全文
0 0
原创粉丝点击