既有的HttpURLConnection存在許多問題java
<!--more-->react
在此以前,可使用如下工具做爲Http客戶端程序員
咱們來看一段HTTP Client的常規用法的樣例 ——
執行GET請求,而後輸出響應體(Response Body)。編程
HttpClient client = HttpClient.newHttpClient(); HttpRequest request = HttpRequest.newBuilder() .uri(URI.create("http://openjdk.java.net/")) .build(); client.sendAsync(request, asString()) .thenApply(HttpResponse::body) .thenAccept(System.out::println) .join();
通常使用JDK 11中的HttpClient的第一步是建立HttpClient對象並進行配置。json
HttpClient client = HttpClient.newBuilder() .version(Version.HTTP_2) .followRedirects(Redirect.SAME_PROTOCOL) .proxy(ProxySelector.of(new InetSocketAddress("www-proxy.com", 8080))) .authenticator(Authenticator.getDefault()) .build();
從HttpRequest的builder組建request服務器
HttpRequest request = HttpRequest.newBuilder() .uri(URI.create("http://openjdk.java.net/")) .timeout(Duration.ofMinutes(1)) .header("Content-Type", "application/json") .POST(BodyPublisher.fromFile(Paths.get("file.json"))) .build()
同步發送API阻塞直到HttpResponse返回多線程
HttpResponse<String> response = client.send(request, BodyHandler.asString()); System.out.println(response.statusCode()); System.out.println(response.body());
client.sendAsync(request, BodyHandler.asString()) .thenApply(response -> { System.out.println(response.statusCode()); return response; } ) .thenApply(HttpResponse::body) .thenAccept(System.out::println);
※CompletableFuture是在java8中加入的,支持組合式異步編程併發
Java NIO爲Java帶來了非阻塞模型。
app
假設如下代碼是一個聊天應用服務器的一部分,該應用以Vert.x框架實現。
(Eclipse Vert.x is a tool-kit for building reactive applications on the JVM.)
向connectHandler方法輸入一個Lambda表達式,每當有用戶鏈接到聊天應用時,都會調用該Lambda表達式。這就是一個回調。
這種方式的好處是,應用沒必要控制線程模型——Vert.x框架爲咱們管理線程,打理好一切相關複雜性,程序員只考慮和回調就夠了。框架
vertx.createServer() .connectHandler(socket -> { socket.dataHandler(new User(socket, this)); }).listen(10_000);
注意,這種設計裏,不共享任何狀態。對象之間經過向事件總線發送消息通訊,根本不須要在代碼中添加鎖或使用synchronized關鍵字。併發編程變得更加簡單。
大量的回調會怎樣?請看如下僞代碼
(1)->{ (2)->{ (3)->{ (4)->{} } } }
大量回調會造成「末日金字塔」。
如何破解? 使用Future
Future1=(1)->{} Future2=(Future1.get())->{} Future3=(Future2.get())->{} Future4=(Future3.get())->{}
但這會形成本來指望的並行處理,變成了串行處理,帶來了性能問題。
咱們真正須要的是將Future和回調聯合起來使用。下面將要講的CompletableFuture就是結合了Future和回調,其要點是組合不一樣實例而無需擔憂末日金字塔問題。
(new CompletableFuture()).thenCompose((1)->{}) .thenCompose((2)->{}) .thenCompose((3)->{}) .thenCompose((4)->{}) .join()
Reactive Streams是一個倡議,它提倡提供一種帶有非阻塞背壓的異步流處理的標準(Reactive Streams is an initiative to provide a standard for asynchronous stream processing with non-blocking back pressure)。
JDK 9中的java.util.concurrent.Flow中的概念,與Reactive Streams是一對一對等的。java.util.concurrent.Flow是Reactive Streams標準的實現之一。
public abstract class HttpRequest { ... public interface BodyPublisher extends Flow.Publisher<ByteBuffer> { ... } }
public abstract class HttpResponse<T> { ... public interface BodyHandler<T> { BodySubscriber<T> apply(int statusCode, HttpHeaders responseHeaders); } public interface BodySubscriber<T> extends Flow.Subscriber<List<ByteBuffer>> { ... } }