异步请求工具类支持CompletableFuture

AsyncHttpClient(AHC)库允许Java应用程序轻松执行HTTP请求并异步处理HTTP响应。 该库还支持WebSocket协议。它的请求处理机制基于netty。作者@TomGranot

基于AsyncHttpClient和CompletableFuture,我编写了一个工具类。
AsyncHttpClient:异步执行请求
CompletableFuture:异步处理结果,并可聚合多个请求结果
完整代码已上传httpAsync

引入

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.asynchttpclient</groupId>
            <artifactId>async-http-client-bom</artifactId>
            <version>LATEST_VERSION</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

<dependencies>
    <dependency>
    	<groupId>org.asynchttpclient</groupId>
    	<artifactId>async-http-client</artifactId>
    </dependency>
</dependencies>

异步http工具类

工具类包含一个客户端【HttpAsyncClient】和一个工具类【HttpAsyncUtil】

package com.isszwy.zhyq.util.httpAsync;

import static org.asynchttpclient.Dsl.asyncHttpClient;

import java.io.IOException;

import io.netty.channel.EventLoopGroup;
import io.netty.channel.epoll.EpollEventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;

import org.asynchttpclient.AsyncHttpClient;
import org.asynchttpclient.AsyncHttpClientConfig;
import org.asynchttpclient.DefaultAsyncHttpClientConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


public class HttpAsyncClient {
	
	private static Logger log = LoggerFactory.getLogger(HttpAsyncClient.class);
	
    private static final int connectTimeoutMilliseconds = 5000;
    private static final int requestTimeoutMilliseconds = 5000;
    private static final int readTimeoutTimeoutMilliseconds = 5000;
    private static final int maxRequestRetry = 2;
    private static EventLoopGroup eventLoopGroup;

    private static AsyncHttpClient asyncHttpClient;
    
    
    private HttpAsyncClient() {
    }

    public static AsyncHttpClient getInstance() {
        if (asyncHttpClient == null) {
            synchronized (AsyncHttpClient.class) {
                if (asyncHttpClient == null) {
                	asyncHttpClient = asyncHttpClient(initConfig());
                	log.info("===HttpAsyncClient初始化完成===");
                }
            }
        }
        return asyncHttpClient;
    }
    

    private static AsyncHttpClientConfig initConfig() {
    	
        String osName = System.getProperty("os.name");
        if ("Linux".equalsIgnoreCase(osName)) {
            eventLoopGroup = new EpollEventLoopGroup();
        } else {
            eventLoopGroup = new NioEventLoopGroup();
        }
        AsyncHttpClientConfig asyncHttpClientConfig = new DefaultAsyncHttpClientConfig
                .Builder()
                .setConnectTimeout(connectTimeoutMilliseconds)
                .setRequestTimeout(requestTimeoutMilliseconds)
                .setReadTimeout(readTimeoutTimeoutMilliseconds)
                .setEventLoopGroup(eventLoopGroup)
                //设置信任所有ssl
                .setUseInsecureTrustManager(true)
                .setMaxRequestRetry(maxRequestRetry)
                .build();
        return asyncHttpClientConfig;
    }

    
    public static void shutdown() {
        if (asyncHttpClient != null) {
            try {
                asyncHttpClient.close();
                eventLoopGroup.shutdownGracefully();
            } catch (IOException exception) {
            	log.error("===HttpAsyncClient关闭异常===",exception);
            }
        }
    }

    
}

package com.isszwy.zhyq.util.httpAsync;

import static io.netty.handler.codec.http.HttpHeaderValues.APPLICATION_JSON;
import static org.asynchttpclient.Dsl.*;
import io.netty.handler.codec.http.DefaultHttpHeaders;
import io.netty.handler.codec.http.HttpHeaders;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.function.Function;

import org.asynchttpclient.Param;
import org.asynchttpclient.Request;
import org.asynchttpclient.RequestBuilder;
import org.asynchttpclient.Response;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class HttpAsyncUtil {
	
	private static Logger log = LoggerFactory.getLogger(HttpAsyncUtil.class);
	
	
	/**
     * 发送application/x-www-form-urlencoded请求
     * @param url
     * @return CompletableFuture<String>
     */
    public static CompletableFuture<String> doGet(String url) {  
        return doGet(url, null,null);  
    }
    
	/**
     * 发送application/x-www-form-urlencoded请求
     * @param url
     * @param param
     * @param header
     * @return CompletableFuture<String>
     */
	public static CompletableFuture<String> doGet(String url, Map<String, String> param,Map<String, String> header) {
		log.info("### request url : {} , param : {} , header : {} !",url,param,header);
    	RequestBuilder request = get(url);
    	if (header != null) {
    		HttpHeaders headers = new DefaultHttpHeaders();
            for (String key : header.keySet()) {
                headers.add(key, header.get(key));
            }
            request.setHeaders(headers);
        } 
    	if (param != null) {
    		List<Param> paramList = new ArrayList<>();  
    		for (String key : param.keySet()) {
    			if(param.get(key) !=null){
    				paramList.add(new Param(key, String.valueOf(param.get(key))));
    			}
    		}
    		request.setFormParams(paramList);
    	}
    	CompletableFuture<String> resultFuture= HttpAsyncClient.getInstance().
	    		prepareRequest(request).execute().toCompletableFuture()
	    					.exceptionally(new Function<Throwable, Response>() {
	    		            	@Override
	    		            	public Response apply(Throwable throwable) {
	    		            		System.out.println("exceptionally - apply :" + throwable.toString());
	    		            		log.error("### send get request error occured !", throwable);
	    		            		return null;
	    		            	}
	    		            })
	    		            .thenApply(response -> {
	    		               if (response.getStatusCode() == 200) { 
	    		            		return response.getResponseBody();
	    		               }else{
	    		            		log.error("### get response error occured !", response.getResponseBody());
		    		               return null;
	    		               }
	    		            });
		return resultFuture;
	}
	
	
	
    public static CompletableFuture<String> doPost(String url) {  
        return doPost(url, null, null);
    }
	
	/**
     * 发送application/octet-stream请求
     * @param url
     * @param param
     * @param header
     * @return CompletableFuture<String>
     */
    public static CompletableFuture<String> doPost(String url, Map<String, String> param,Map<String, String> header) {
    	log.info("### request url : {} , param : {} , header : {} !",url,param,header);
    	RequestBuilder request = post(url);
    	if (header != null) {
    		HttpHeaders headers = new DefaultHttpHeaders();
            for (String key : header.keySet()) {
                headers.add(key, header.get(key));
            }
            request.setHeaders(headers);
        } 
    	if (param != null) {
    		List<Param> paramList = new ArrayList<>();  
    		for (String key : param.keySet()) {
    			if(param.get(key) !=null){
    				paramList.add(new Param(key, String.valueOf(param.get(key))));
    			}
    		}
    		request.setFormParams(paramList);
    	}
    	CompletableFuture<String> resultFuture= HttpAsyncClient.getInstance().
	    		prepareRequest(request).execute().toCompletableFuture()
	    					.exceptionally(new Function<Throwable, Response>() {
	    		            	@Override
	    		            	public Response apply(Throwable throwable) {
	    		            		System.out.println("exceptionally - apply :" + throwable.toString());
	    		            		log.error("### send Post request error occured !", throwable);
	    		            		return null;
	    		            	}
	    		            })
	    		            .thenApply(response -> {
	    		               if (response.getStatusCode() == 200) { 
	    		            		return response.getResponseBody();
	    		               }else{
	    		            		log.error("### get Post response error occured !", response.getResponseBody());
		    		               return null;
	    		               }
	    		            });
		return resultFuture;
    }
	
	/**
     * 发送application/json请求
     * @param url
     * @param json
     * @return CompletableFuture<String>
     */
	public static CompletableFuture<String> doPostJson(String url, String json){
        Request request = post(url).setBody(json).setHeader("content-type", APPLICATION_JSON).build();
	    CompletableFuture<String> resultFuture= HttpAsyncClient.getInstance().
	    		prepareRequest(request).execute().toCompletableFuture()
	    					.exceptionally(new Function<Throwable, Response>() {
	    		            	@Override
	    		            	public Response apply(Throwable throwable) {
	    		            		System.out.println("exceptionally - apply :" + throwable.toString());
	    		            		log.error("### send PostJson request error occured !", throwable);
	    		            		return null;
	    		            	}
	    		            })
	    		            .thenApply(response -> {
	    		               if (response.getStatusCode() == 200) { 
	    		            		return response.getResponseBody();
	    		               }else{
	    		            		log.error("### get PostJson response error occured !", response.getResponseBody());
		    		               return null;
	    		               }
	    		            });
		return resultFuture;
	}

}

使用

CompletableFuture<String> resultHik = HttpAsyncUtil.doPostJson(HIKURL, JSON.toJSONString(paramsMap));
CompletableFuture<String> resultData = HttpAsyncUtil.doPost(url, paramMap, null);

示例

CompletableFuture<String> resultHik = HttpAsyncUtil.doPostJson(HIKURL, JSON.toJSONString(hikParamsMap));
CompletableFuture<String> resultData = HttpAsyncUtil.doPost(url, paramMap, null);


CompletableFuture<List<Map<String,Object>>> endResult = resultData.thenCombine(resultHik, (res1, res2) -> {
	Map<String,Object> hikResult = JSON.parseMap(res2);
	
	Map<String,Object> dataResult = JSON.parseMap(res1);
	List<Map<String,Object>> result = null;
	if(hikResult!= null && "0".equals(hikResult.get("code")) 
			&& dataResult!= null && "200".equals(dataResult.get("code"))){
		Map<String, Object> data = (Map<String, Object>) hikResult.get("data");
		List<Map<String,Object>> hikList = (List<Map<String,Object>>) data.get("list");

		Map<String,Object> dataDa = (Map<String,Object>) dataResult.get("data");
		List<Map<String,Object>> dataList =(List<Map<String, Object>>) dataDa.get("data");
		for(Map<String,Object> hikObj:hikList){
			for(Map<String,Object> dataObj:dataList){
				if(hikObj.get("cameraIndexCode").equals(dataObj.get("CAMERAINDEXCODE"))){
					hikObj.put("altitude", dataObj.get("LATITUDE"));
					hikObj.put("longitude", dataObj.get("LONGITUDE"));
				}
			}
		}
		result = hikList;
	}
	return result;
});

性能测试

一个主线程循环执行1、2、3、10、20、30次(N)请求,异步和同步请求的响应时间(单位ms,包含结果逻辑处理的时间)。请求执行一次响应时间没有明显变化,请求执行多次,性能有明显提升。

请求次数异步同步性能提升
14048ms4688ms14%
24928ms8484ms42%
35970ms11043ms46%
1013583ms33147ms59%
2022873ms65358ms65%
3038014ms96989ms61%

https://github.com/AsyncHttpClient/async-http-client
https://zhuanlan.zhihu.com/p/363832799

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值