目录
当程序需要连接多个服务器端,或与同一个服务器端进行频繁交互时,使用异步HTTP客户端会极大的提高程序处理的吞吐量。
当前比较流行的支持回调的异步HTTP客户端:
一、Reactor Netty
Reactor Netty Reference Guide
基于Netty,实现reactive streams,支持WebSocket
<dependency>
<groupId>io.projectreactor.netty</groupId>
<artifactId>reactor-netty-http</artifactId>
<version>1.0.32</version>
</dependency>
连接池配置:
ConnectionProvider.create("connMgr", 4)
线程池配置:
LoopResources.create("reactor-", 4, false) 或 -Dreactor.netty.ioWorkerCount
默认线程数:
Runtime.getRuntime().availableProcessors()
示例:
final CountDownLatch latch1 = new CountDownLatch(1);
ConnectionProvider connectionProvider = ConnectionProvider.builder("custom") //
.maxConnections(50)//
.maxIdleTime(Duration.ofSeconds(20)) //
.maxLifeTime(Duration.ofSeconds(60))//
.pendingAcquireTimeout(Duration.ofSeconds(60)) //
.evictInBackground(Duration.ofSeconds(120))//
.metrics(true)//
.build();
HttpClient client = HttpClient.create(connectionProvider) // 设置连接数
.runOn(LoopResources.create("reactor-", 4, false)); // 设置线程数
client.get().uri("https://www.apache.org").responseContent().aggregate().asString().subscribe(s -> {
System.out.println(Thread.currentThread().getName());
System.out.println(s);
latch1.countDown();
});
latch1.await();
二、 Apache HttpAsyncClient
Apache HttpComponents – HttpAsyncClient Overview
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpasyncclient</artifactId>
<version>4.1.5</version>
</dependency>
一个用于发送http请求的线程,线程名
Thread[pool-1-thread-1]
多个用于处理http响应的线程,线程名
Thread[I/O dispatcher i]
默认线程数由Runtime.getRuntime().availableProcessors()确定,可通过如下方式配置自定义线程数
IOReactorConfig.Builder.setDefaultMaxIoThreadCount(int);
示例:
IOReactorConfig.Builder builder = IOReactorConfig.custom();
builder.setIoThreadCount(3); // 设置线程数
IOReactorConfig ioReactorConfig = builder.build();
PoolingNHttpClientConnectionManager connectionManager = new PoolingNHttpClientConnectionManager(
new DefaultConnectingIOReactor(ioReactorConfig));
connectionManager.setMaxTotal(200); // 设置最大连接数
connectionManager.setDefaultMaxPerRoute(50); // 设置每个路由的最大连接数
HttpAsyncClientBuilder httpAsyncClientBuilder = HttpAsyncClients.custom();
httpAsyncClientBuilder.useSystemProperties() //
.setKeepAliveStrategy(new DefaultConnectionKeepAliveStrategy()) //
.setConnectionManager(connectionManager);
CloseableHttpAsyncClient httpclient = httpAsyncClientBuilder.build();
try {
// Start the client
httpclient.start();
// One most likely would want to use a callback for operation result
final CountDownLatch latch1 = new CountDownLatch(1);
final HttpGet request2 = new HttpGet("https://www.apache.org/");
httpclient.execute(request2, new FutureCallback<HttpResponse>() {
public void completed(final HttpResponse response2) {
System.out.println(Thread.currentThread().getName() + ":completed");
latch1.countDown();
System.out.println(request2.getRequestLine() + "->" + response2.getStatusLine());
}
public void failed(final Exception ex) {
System.out.println(Thread.currentThread().getName() + ":failed");
latch1.countDown();
System.out.println(request2.getRequestLine() + "->" + ex);
}
public void cancelled() {
System.out.println(Thread.currentThread().getName() + ":cancelled");
latch1.countDown();
System.out.println(request2.getRequestLine() + " cancelled");
}
});
latch1.await();
} finally {
httpclient.close();
}
三、AsyncHttpClient
https://github.com/AsyncHttpClient/async-http-client
基于Netty,实现reactive streams,支持WebSocket
参考文档:
Asynchronous HTTP with async-http-client in Java | Baeldung
<dependency>
<groupId>org.asynchttpclient</groupId>
<artifactId>async-http-client</artifactId>
<version>2.12.3</version>
</dependency>
默认线程数
-Dorg.asynchttpclient.ioThreadsCount
默认最大连接数
-Dorg.asynchttpclient.maxConnections
线程名
AsyncHttpClient-timer-1-1
AsyncHttpClient-3-1
示例:
final CountDownLatch latch1 = new CountDownLatch(1);
DefaultAsyncHttpClientConfig.Builder builder = new DefaultAsyncHttpClientConfig.Builder();
DefaultAsyncHttpClientConfig config = builder.setMaxConnections(200) //
.setIoThreadsCount(10) //
.setKeepAlive(true) //
.build();
try (AsyncHttpClient asyncHttpClient = new DefaultAsyncHttpClient(config);) {
ListenableFuture<Response> whenResponse = asyncHttpClient.prepareGet("https://www.apache.org/").execute();
Runnable callback = () -> {
try {
Response response = whenResponse.get();
System.out.println(response);
latch1.countDown();
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
};
//Executor executor = Executors.newSingleThreadExecutor();
whenResponse.addListener(callback, null);
latch1.await();
}
四、Grizzly Async Http Client
https://github.com/javaee/grizzly-ahc
https://github.com/eclipse-ee4j/grizzly-ahc
<dependency>
<groupId>org.glassfish.grizzly</groupId>
<artifactId>grizzly-http-client</artifactId>
<version>1.15</version>
</dependency>
selector线程数:
Runtime.getRuntime().availableProcessors() > 5 ? Runtime.getRuntime().availableProcessors() : 5;
线程名:
grizzly-ahc-kernel(i) SelectorRunner
callback线程池可指定
示例:
final CountDownLatch latch1 = new CountDownLatch(1);
AsyncHttpClientConfig.Builder builder = new AsyncHttpClientConfig.Builder();
builder.setAllowPoolingConnections(true) //
.setMaxConnections(200) //
.setIOThreadMultiplier(0) //
.setExecutorService(Executors.newSingleThreadScheduledExecutor());
AsyncHttpClient asyncHttpClient = new AsyncHttpClient(builder.build());
asyncHttpClient.prepareGet("https://www.apache.org/").execute(new AsyncCompletionHandler<Response>() {
@Override
public Response onCompleted(Response response) throws Exception {
String body = response.getResponseBody();
System.out.println(body);
latch1.countDown();
return response;
}
@Override
public void onThrowable(Throwable t) {
// Something wrong happened.
}
});
latch1.await();
五、OkHttp
GitHub - square/okhttp: Square’s meticulous HTTP client for the JVM, Android, and GraalVM.
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>4.11.0</version>
</dependency>
回调线程都是临时创建的
示例:
OkHttpClient.Builder builder = new OkHttpClient.Builder();
builder.connectionPool(new ConnectionPool(10, 60, TimeUnit.SECONDS));
OkHttpClient client = builder.build();
String url = "https://www.apache.org/";
Request request = new Request.Builder().url(url).build();
final CountDownLatch latch1 = new CountDownLatch(1);
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call arg0, IOException arg1) {
}
@Override
public void onResponse(Call arg0, Response response) throws IOException {
String body = response.body().string();
System.out.println(body);
latch1.countDown();
}
});
latch1.await();